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.
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í.
Como acessarHow to openCómo acceder
- É 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.
- 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.
- 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.
- 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.
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.
Status e estadosStatus & statesEstado y estados
Estados da tela inteiraWhole-screen statesEstados de la pantalla completa
Só 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ó".
| AtalhoShortcutAtajo | O que o número contaWhat the number countsQué cuenta el número |
|---|---|
| Pedidos pendentesPending ordersPedidos pendientes | Pedidos 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ía | Quantidade 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). |
| CasosCasesCasos | Casos 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ê). |
| TarefasTasksTareas | Só 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 · Pistas | Sem 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
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%.
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
menuConfigdo 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'smenuConfig: 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 delmenuConfigdel 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).
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
- _load() + EMC + Communications + contadoresHomeNotifier + HomeState
- execute(source: local)GetHomeKPIUseCase
- getHomeKpis(source: local)HomeKPIRepositoryImpl
- toDomainHomeKpiEntitydomain
- getHomeKpis()HomeKPILocalDataSource
Os contadores dos atalhos entram nesse mesmo _load(), por um caminho paralelo: o GetRepActionsPendingCountsUseCase lê seis 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
- _bumpRevisions(types)listenDataRevision7 DataSyncType
- toDTO → toDomain → saveHomeKpisHomeKPIModelObjectBox · write-through
- getHomeKpis(locationHierarchySfid)HomeKPIRemoteDataSourcegRPC · KpiConectaRepService
- execute(source: remote)GetHomeKPIUseCase · GetCommunicationsUseCase
- isStale(type, lastSyncAt, now)DataFreshnessConfigTTL por tipo · EMC
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.
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ções — Proto (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 representations — Proto (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 representaciones — Proto (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.protorpc getHomeKpis(KpiRequest) returns (KpiReply)
path /mn.bat.conectarep.streambridge.KpiConectaRepService/getHomeKpis
KpiRequestlocationHierarchySfidstring· #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)dateReferencestring· #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 repositorylastModifiedDatestring· #3 · optional · não plumbado em camada nenhumaoptional · not plumbed in any layeroptional · no plumbeado en ninguna capa
KpiReplycommercialPillars¹ · visitsOfTheDay · ordersOfTheDay · volumeOfTheDay · deliveryVolumeOfTheDay¹ · modiCoverage¹ · sop¹ · repeated bullsEye · endJourney — 9 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.protorpc getCommunications(CommunicationsRequest) returns (CommunicationsReply)
path /mn.bat.conectarep.streambridge.CommunicationsConectaRepService/getCommunications
CommunicationsRequestlocationHierarchySfidstring· #1 · idem — único campo realmente enviadosame — the only field actually sentídem — el único campo realmente enviadodateReferencestring· #2 · optional · parâmetro do datasource sem calleroptional · datasource parameter with no calleroptional · parámetro del datasource sin callerlastModifiedDatestring· #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)
CommunicationsReplyrepeated Communication communications — os 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
Campo Proto DTO Model Entity lastSyncAt— — DateTimeDateTime commercialPillarsCommercialPillars¹ CommercialPillarsDTO? ToOne<CommercialPillarsModel>CommercialPillarsEntity? visitsOfTheDayBasicKpi BasicKPIDTO ToOne<BasicKPIModel>BasicKpiEntity ordersOfTheDayBasicKpi BasicKPIDTO ToOne<BasicKPIModel>BasicKpiEntity volumeOfTheDayVolumeKpi VolumeKPIDTO ToOne<VolumeKPIModel>VolumeKpiEntity deliveryVolumeOfTheDayVolumeKpi¹ VolumeKPIDTO? ToOne<VolumeKPIModel>VolumeKpiEntity? modiCoverageBasicKpi¹ BasicKPIDTO? ToOne<BasicKPIModel>BasicKpiEntity? sopSopKpi¹ SopKPIDTO? ToOne<SopKPIModel>SopKpiEntity? bullsEyerepeated PillarsKpi List<PillarKPIDTO> ToMany<PillarKPIModel>List<PillarKpiEntity> endJourneyJourneyKpi JourneyKPIDTO ToOne<JourneyKPIModel>JourneyKpiEntity CommercialPillars HomeKpi.commercialPillars¹ 3 camposfieldscampos
Campo Proto DTO Model Entity totalTargetdouble double double double totalRealizeddouble double double double pillarsListrepeated PillarsKpi List<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
Campo Proto DTO Model Entity kpiNamestring String String String targetdouble double double double realizeddouble double double double percentagedouble double double double 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
Campo Proto DTO Model Entity categorystring¹ String? String? String? targetdouble double double double realizeddouble double double double differencedouble double double double percentagedouble double double double totaldouble¹ double? double? double? detailsrepeated DetailKpi List<DetailKPIDTO> ToMany<DetailKPIModel>List<DetailKpiEntity> parentType— — String— DetailKpi BasicKpi.details[] · SopCategoryItem.periods[] 8 campos + getterfields + gettercampos + getter
Campo Proto DTO Model Entity detailTypestring¹ String? String? String? periodstring¹ String? String? String? targetdouble double double double realizeddouble double double double differencedouble double double double percentagedouble double double double totaldouble¹ double? double? double? visitsrepeated string List<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
Campo Proto DTO Model Entity categoriesrepeated BasicKpi List<BasicKPIDTO> ToMany<BasicKPIModel>List<BasicKpiEntity> parentType— — String— SopKpi HomeKpi.sop¹ 1 campofieldcampo
Campo Proto DTO Model Entity categoriesrepeated SopCategory List<SopCategoryDTO> ToMany<SopCategoryModel>List<SopCategoryEntity> SopCategory SopKpi.categories[] 2 camposfieldscampos
Campo Proto DTO Model Entity categorystring String String String itemsrepeated SopCategoryItem List<SopCategoryItemDTO> ToMany<SopCategoryItemModel>List<SopCategoryItemEntity> SopCategoryItem SopCategory.items[] 2 camposfieldscampos
Campo Proto DTO Model Entity typestring String String String periodsrepeated DetailKpi List<DetailKPIDTO> ToMany<DetailKPIModel>List<DetailKpiEntity>
JourneyKpi HomeKpi.endJourney 1 campofieldcampo
Campo Proto DTO Model Entity kpisrepeated KpiInfo List<ActionKPIDTO> ToMany<ActionKPIModel>List<ActionKpiEntity> ActionKpi JourneyKpi.kpis[] · proto KpiInfo 2 camposfieldscampos
Campo Proto DTO Model Entity kpiNamestring String String String valuedouble double double double
Communications CommunicationsReply 2 camposfieldscampos
Campo Proto DTO Model Entity lastSyncAt— DateTime? DateTimeDateTime? itemsrepeated Communication List<CommunicationDTO> ToMany<CommunicationModel>List<CommunicationEntity> Communication Communications.items[] 8 camposfieldscampos
Campo Proto DTO Model Entity sfidstring String String String typestring CommunicationTypeString CommunicationType namestring String String String descriptionstring String String String imageUrlstring String String String priorityint32 int int int startDatestring DateTime?DateTime? DateTime? endDatestring DateTime?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ón | MétodoMethodMétodo | Onde/quandoWhere/whenDónde/cuándo |
|---|---|---|
| JSON → DTO | fromMap | mock (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 → DTO | toDTO · toCommunicationsDTO | remote; 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 → Entity | toDomain | é onde o HomeKpi.lastSyncAt é cunhado (DateTimeUtils.now())where HomeKpi.lastSyncAt is minted (DateTimeUtils.now())donde el HomeKpi.lastSyncAt es acuñado (DateTimeUtils.now()) |
| Entity → Model | toModel | grava 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 → Entity | toDomain | leitura 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
ToOneno Model (os 8 blocos deHomeKpi) e toda repetida viraToMany(bullsEye,pillarsList,details,categories,items,periods,kpis,Communications.items).Every optional or required sub-message becomesToOnein the Model (HomeKpi's 8 blocks) and every repeated one becomesToMany(bullsEye,pillarsList,details,categories,items,periods,kpis,Communications.items).Toda sub-mensaje opcional u obligatoria se vuelveToOneen el Model (los 8 bloques deHomeKpi) y toda repetida se vuelveToMany(bullsEye,pillarsList,details,categories,items,periods,kpis,Communications.items). DetailKpi.visitsé a exceção:repeated stringcontinuaList<String>no ObjectBox (lista escalar, não relação).DetailKpi.visitsis the exception:repeated stringstaysList<String>in ObjectBox (scalar list, not a relation).DetailKpi.visitses la excepción:repeated stringsigue siendoList<String>en ObjectBox (lista escalar, no relación).HomeKpi.lastSyncAtnão existe no proto nem no DTO — é cunhado no mapper DTO→Entity comDateTimeUtils.now()e daí persistido no Model. EmCommunicationsele existe já no DTO, e o delta é de nulidade:DateTime?na Entity contraDateTimenão-nulo no Model — guardado por umStateErrornotoModel().HomeKpi.lastSyncAtexists neither in the proto nor in the DTO — it is minted in the DTO→Entity mapper withDateTimeUtils.now()and persisted into the Model from there. InCommunicationsit already exists on the DTO, and the delta is one of nullability:DateTime?on the Entity against non-nullDateTimeon the Model — guarded by aStateErrorintoModel().HomeKpi.lastSyncAtno existe en el proto ni en el DTO — es acuñado en el mapper DTO→Entity conDateTimeUtils.now()y de ahí persistido en el Model. EnCommunicationsya existe en el DTO, y el delta es de nulidad:DateTime?en la Entity contraDateTimeno-nulo en el Model — resguardado por unStateErroren eltoModel().- 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. Otypeainda volta aStringno Model (guarda ovalue) 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.typethen goes back toStringin the Model (storing thevalue) 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. Eltypevuelve aStringen el Model (guarda elvalue) y se reparsea en la lectura. parentType(emBasicKpieVolumeKpi) existe só no Model: é um discriminador de persistência preenchido com literais notoModel()("visitsOfTheDay","ordersOfTheDay","volumeOfTheDay","deliveryVolumeOfTheDay","modiCoverage") e nunca lido de volta.parentType(onBasicKpiandVolumeKpi) exists only in the Model: a persistence discriminator filled with literals intoModel()("visitsOfTheDay","ordersOfTheDay","volumeOfTheDay","deliveryVolumeOfTheDay","modiCoverage") and never read back.parentType(enBasicKpiyVolumeKpi) existe solo en el Model: es un discriminador de persistencia llenado con literales en eltoModel()("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
KpiInfodo proto viraActionKPIDTO/ActionKpiEntity/ActionKPIModel. O campo continuakpis.A message rename, not a field one: the proto'sKpiInfomessage becomesActionKPIDTO/ActionKpiEntity/ActionKPIModel. The field stayskpis.Renombre de mensaje, no de campo: el mensajeKpiInfodel proto se vuelveActionKPIDTO/ActionKpiEntity/ActionKPIModel. El campo sigue siendokpis.
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
sourcedefault élocal, então a abertura da tela cai no cache;refresh()passaremote.Three guard-clauses, in this exact order. The defaultsourceislocal, so opening the screen lands in cache;refresh()passesremote.Tres guard-clauses, en este orden exacto. Elsourcepor defecto eslocal, así que abrir la pantalla cae en el caché;refresh()pasaremote.
- 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 viraNetworkFailure.→_fetchFromCacheOrFail()— non-null cache wins; empty cache becomesNetworkFailure.→_fetchFromCacheOrFail()— caché no-nulo gana; caché vacío se vuelveNetworkFailure. - 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 comresource.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 withresource.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 conresource.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 returnsSuccess(null)(not a failure).Lee la única fila del ObjectBox. Nunca va a la red; caché vacío devuelveSuccess(null)(no es falla).
getCachedHomeKpisLastSyncAt() HomeKPIRepositoryImpl hook do sweepsweep hookhook del sweep
- Retorno
Future<DateTime?>- ComportamentoBehaviorComportamiento
- Lê só o
lastSyncAtda linha, sem mapear a árvore inteira. É o que oDataSyncOrchestratorconsulta para decidir se o tipohomeKpiestá obsoleto. Erro degrada paranull— enullconta como obsoleto.Reads only the row'slastSyncAt, without mapping the whole tree. It is what theDataSyncOrchestratorchecks to decide whether thehomeKpitype is stale. An error degrades tonull— andnullcounts as stale.Lee solo ellastSyncAtde la fila, sin mapear el árbol entero. Es lo que elDataSyncOrchestratorconsulta para decidir si el tipohomeKpiestá obsoleto. Un error degrada anull— ynullcuenta 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
lastSyncAtda 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'slastSyncAt— 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 ellastSyncAtde 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 isSuccess(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 esSuccess(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 só olocationHierarchySfid, grava e devolve; em falha, cache não-nulo vence, cache vazio propaga a falha.→_fetchFromRemoteWithFallback()— sends only thelocationHierarchySfid, saves and returns; on failure, a non-null cache wins, an empty cache propagates the failure.→_fetchFromRemoteWithFallback()— envía solo ellocationHierarchySfid, 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
saveCommunications({entity}) CommunicationsRepositoryImpl write-through
- Retorno
Future<Result<void, Failure>>- ComportamentoBehaviorComportamiento
- Chamado nos dois caminhos de fetch (mock e remoto). O
toModel()lançaStateErrorse olastSyncAtvier nulo — só entidades já estampadas por um fetch podem ser persistidas.Called on both fetch paths (mock and remote).toModel()throws aStateErroriflastSyncAtis null — only entities already stamped by a fetch can be persisted.Llamado en los dos caminos de fetch (mock y remoto). EltoModel()lanzaStateErrorsi ellastSyncAtviene 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.
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
KpiRequestcomlocationHierarchySfid;dateReferencesó se não-nulo.lastModifiedDatenunca é setado.Builds aKpiRequestwithlocationHierarchySfid;dateReferenceonly when non-null.lastModifiedDateis never set.Arma unKpiRequestconlocationHierarchySfid;dateReferencesolo si no es nulo.lastModifiedDatenunca se setea. - Fluxo de usoUsage flowFlujo de uso
- Chamado só pelo
_fetchFromRemoteWithFallbackdo repository, que já resolveu a hierarquia. Canalstreambridge, 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.streambridgechannel, with the global interceptors (including the 15 s deadline when the connection is unstable).Llamado solo por el_fetchFromRemoteWithFallbackdel repository, que ya resolvió la jerarquía. Canalstreambridge, con los interceptores globales (incluido el deadline de 15 s cuando la conexión está inestable). - Tratamento de erroError handlingManejo de error
GrpcError→GrpcExceptionHandler.handle; qualquer outro →ServerException("Failed to fetch HomeKPI from gRPC"), com log.GrpcError→GrpcExceptionHandler.handle; anything else →ServerException("Failed to fetch HomeKPI from gRPC"), logged.GrpcError→GrpcExceptionHandler.handle; cualquier otro →ServerException("Failed to fetch HomeKPI from gRPC"), con log.
getHomeKpis({locationHierarchySfid, dateReference?})
- Retorno
Future<HomeKPIDTO>- UsoUseUso
- Único método. Converte o
KpiReplypara DTO na saída (toDTO).The only method. Converts theKpiReplyto a DTO on the way out (toDTO).Único método. Convierte elKpiReplya 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
CacheExceptioncom mensagem própria eshouldLog: true.Every method wraps into aCacheExceptionwith its own message andshouldLog: true.Todo método envuelve enCacheExceptioncon mensaje propio yshouldLog: 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, notoDomain— cheap enough for the sweep to run every minute.Lee solo el timestamp, sintoDomain— 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.CallsclearHomeKpis()first and then writes the new model — full replacement, never a merge.LlamaclearHomeKpis()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.jsonou{mercado}_real_home_kpi.json.None. The file is picked by market + mode:{market}_home_kpi.jsonor{market}_real_home_kpi.json.Ninguno. El archivo se elige por mercado + modo:{mercado}_home_kpi.jsono{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 viraCacheException.In real-mock mode a missing asset returns"{}"silently (a Home with no indicators at all); in synthetic mode a missing asset becomes aCacheException.En modo real-mock, un asset ausente devuelve"{}"en silencio (Home sin ningún indicador); en modo sintético, un asset ausente se vuelveCacheException.
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
CommunicationsRequestcomlocationHierarchySfid;dateReferencese não-nulo elastModifiedDatese não-nulo e não-vazio (guarda assimétrica). Nenhum caller preenche os dois últimos.CommunicationsRequestwithlocationHierarchySfid;dateReferencewhen non-null andlastModifiedDatewhen non-null and non-empty (asymmetric guard). No caller fills the last two.CommunicationsRequestconlocationHierarchySfid;dateReferencesi no es nulo ylastModifiedDatesi 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 norefresh()e no sweep, nunca na abertura.Samestreambridgechannel. Called onrefresh()and on the sweep, never on open.Mismo canalstreambridge. Llamado en elrefresh()y en el sweep, nunca en la apertura. - Tratamento de erroError handlingManejo de error
GrpcError→GrpcExceptionHandler.handle; outro →ServerException("Failed to fetch Communications from gRPC").GrpcError→GrpcExceptionHandler.handle; other →ServerException("Failed to fetch Communications from gRPC").GrpcError→GrpcExceptionHandler.handle; otro →ServerException("Failed to fetch Communications from gRPC").
getCommunications({locationHierarchySfid, dateReference?, lastModifiedDate?})
- Retorno
Future<CommunicationsDTO>- UsoUseUso
- Único método. O
toCommunicationsDTO()já estampalastSyncAtcom o relógio.The only method.toCommunicationsDTO()already stampslastSyncAtfrom the clock.Único método. EltoCommunicationsDTO()ya estampalastSyncAtcon el reloj.
Local CommunicationsLocalDataSource ObjectBox
- EnvioSendEnvío
- Nenhum. Duas boxes: o container e os itens (
sfidindexado).None. Two boxes: the container and the items (indexedsfid).Ninguno. Dos boxes: el contenedor y los ítems (sfidindexado). - Tratamento de erroError handlingManejo de error
CacheExceptionpor método, com log.A per-methodCacheException, logged.CacheExceptionpor 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.jsonou{mercado}_real_communications.json; a chave lida écommunications.None.{market}_communications.jsonor{market}_real_communications.json; the key read iscommunications.Ninguno.{mercado}_communications.jsono{mercado}_real_communications.json; la clave leída escommunications. - 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
fromMapdo container estampalastSyncAtcom o relógio e ignora entradas que não sejam objeto.The only method; the container'sfromMapstampslastSyncAtfrom the clock and skips non-object entries.Único método; elfromMapdel contenedor estampalastSyncAtcon el reloj e ignora entradas que no sean objeto.
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
| case | value | Módulo da HomeHome moduleMódulo de la Home |
|---|---|---|
endJourney | end_journey | pílula "encerrar jornada" na saudação"end journey" pill in the greetingpíldora "cerrar jornada" en el saludo |
communications | communications | carrossel de comunicadoscommunications carouselcarrusel de comunicados |
repActions | rep_actions | grade de atalhos (usa details)shortcut grid (uses details)grilla de atajos (usa details) |
bullsEye | bulls_eye | cartão bulls eye (usa details)bulls eye card (uses details)tarjeta bulls eye (usa details) |
commercialPillars | commercial_pillars | cartão de pilares comerciais (usa details)commercial pillars card (uses details)tarjeta de pilares comerciales (usa details) |
visitsOfTheDay | visits_of_the_day | rosca de visitas do diavisits-of-the-day donutdona de visitas del día |
ordersOfTheDay | orders_of_the_day | rosca de pedidos do diaorders-of-the-day donutdona de pedidos del día |
volumeOfTheDay | volume_of_the_day | cartão/carrossel de volumevolume card/carouseltarjeta/carrusel de volumen |
deliveryVolumeOfTheDay | delivery_volume_of_the_day | cartão expansível de volume de entregaexpandable delivery-volume cardtarjeta expansible de volumen de entrega |
vuseCoverage | vuse_coverage | cartão de cobertura (lê o KPI modiCoverage)coverage card (reads the modiCoverage KPI)tarjeta de cobertura (lee el KPI modiCoverage) |
sop | sop | cartão SOP (usa filterOptions + periodOptions)SOP card (uses filterOptions + periodOptions)tarjeta SOP (usa filterOptions + periodOptions) |
conectaVoce | conecta_voce | sem 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) |
dailyKpis | daily_kpis | sem 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
| case | value | Navega paraNavigates toNavega a |
|---|---|---|
homeModulePendingOrders | pending_orders | aba Pedidos, pré-filtrada em "pendentes"Orders tab, pre-filtered to "pending"pestaña Pedidos, prefiltrada en "pendientes" |
homeModuleDeliveriesOfTheDay | deliveries_of_the_day | DeliveriesOfTheDayPage |
homeModuleVisitsOfTheDay | visits_of_the_day | aba VisitasVisits tabpestaña Visitas |
homeModuleCases | cases | CasesPage |
homeModuleConectaVoce | conecta_voce | ConectaVoceHubPage |
homeModuleTasks | tasks | TasksPage |
homeModuleRetails | retails | RetailsPage |
homeModulePrimeSimulator | prime_simulator | PrimeSimulatorPage |
homeModuleNewAccount | new_account | NewRetailTypeSelectionPage |
homeModuleClues | clues | ClavePage (entrada geográfica)ClavePage (geographic entry)ClavePage (entrada geográfica) |
homeModuleCollectionsManagement | collections_management | CollectionsPage |
homeModuleReturnsArea | returns_area | — aviso "em desenvolvimento"— "under development" notice— aviso "en desarrollo" |
homeModuleChatBotVoll | chat_bot_voll | — aviso "em desenvolvimento" (nenhum mercado declara)— "under development" notice (no market declares it)— aviso "en desarrollo" (ningún mercado lo declara) |
bullsEyeShipmentFmc | shipment_fmc | barra do bulls eyebulls eye barbarra del bulls eye |
bullsEyeShipmentNc | shipment_nc | barra do bulls eyebulls eye barbarra del bulls eye |
bullsEyeTargetFmcSoq | target_fmc_soq | barra do bulls eyebulls eye barbarra del bulls eye |
bullsEyeTargetNcSoq | target_nc_soq | barra do bulls eyebulls eye barbarra del bulls eye |
bullsEyeCustomerExecution | customer_execution | barra do bulls eyebulls eye barbarra del bulls eye |
bullsEyeB2bEngagement | b2b_engagement | barra do bulls eyebulls eye barbarra del bulls eye |
bullsEyeCredit | credit | barra do bulls eyebulls eye barbarra del bulls eye |
commercialPillarsOverdue | overdue | barra de pilar comercialcommercial pillar barbarra de pilar comercial |
commercialPillarsFatPartnership | fat_partnership | barra de pilar comercialcommercial pillar barbarra de pilar comercial |
commercialPillarsEffectiveness | effectiveness | barra de pilar comercialcommercial pillar barbarra de pilar comercial |
commercialPillarsPrimeCoverage | prime_coverage | barra de pilar comercialcommercial pillar barbarra de pilar comercial |
commercialPillarsProductivity | productivity | barra de pilar comercialcommercial pillar barbarra de pilar comercial |
commercialPillarsCapilarity | capilarity | barra de pilar comercialcommercial pillar barbarra de pilar comercial |
commercialPillarsPositivationPartnership | positivation_partnership | barra de pilar comercialcommercial pillar barbarra de pilar comercial |
commercialPillarsBoostPlan | boost_plan | barra 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
| case | value | Efeito na HomeEffect on the HomeEfecto en la Home |
|---|---|---|
simple | simple | rosca sem quebra de detalhe (default do ModuleConfig)donut with no detail breakdown (the ModuleConfig default)dona sin desglose de detalle (default del ModuleConfig) |
detailed | detailed | abre 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 |
carousel | carousel | uma 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) |
productImages | product_images | na 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 |
list | list | não usado por nenhum módulo da Homenot used by any Home moduleno usado por ningún módulo de la Home |
unknown | unknown | fallback 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
| case | value | chave de traduçãotranslation keyclave de traducción |
|---|---|---|
shipmentFmc | shipment_fmc | bullsEyeShipmentFmc |
shipmentNc | shipment_nc | bullsEyeShipmentNc |
targetFmcSoq | target_fmc_soq | bullsEyeTargetFmcSoq |
targetNcSoq | target_nc_soq | bullsEyeTargetNcSoq |
customerExecution | customer_execution | bullsEyeCustomerExecution |
b2bEngagement | b2b_engagement | bullsEyeB2bEngagement |
credit | credit | bullsEyeCredit |
unknown | unknown | nenhuma → 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
| case | value | chave de traduçãotranslation keyclave de traducción |
|---|---|---|
overdue | overdue | commercialPillarsOverdue |
fatPartnership | fat_partnership | commercialPillarsFatPartnership |
effectiveness | effectiveness | commercialPillarsEffectiveness |
primeCoverage | prime_coverage | commercialPillarsPrimeCoverage |
productivity | productivity | commercialPillarsProductivity |
capilarity | capilarity | commercialPillarsCapilarity |
positivationPartnership | positivation_partnership | commercialPillarsPositivationPartnership |
boostPlan | boost_plan | commercialPillarsBoostPlan |
unknown | unknown | nenhuma → 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
| case | value | ObservaçãoNoteObservación |
|---|---|---|
all | all | també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 |
delivered | delivered | os 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
| case | value | Rótulo na HomeLabel on the HomeRótulo en la Home |
|---|---|---|
monthToDate | mtd | "até hoje""month-to-date""hasta hoy" |
month | month | "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
| case | wireValue | label |
|---|---|---|
fmc | fmc | FMC |
thpDevices | thp_devices | THP Devices |
thpSticks | thp_sticks | THP Sticks |
vapourDevices | vapour_devices | Vapour Devices |
vapourLiquids | vapour_liquids | Vapour Liquids |
oral | oral | Oral |
ryo | ryo | RYO |
myo | myo | MYO |
otp | otp | OTP |
otpAccessories | otp_accessories | OTP Accessories |
otherEa | other_ea | Other EA |
otherUnit | other_unit | Other UNIT |
otherPce | other_pce | Other PCE |
vuse | vuse | VUSE |
partnership | partnership | Partnership |
nc | nc | NC |
unknown | "" | "" |
fromValue({value})- Casa por
wireValueou porlabel, sem diferenciar maiúsculas, e ignora o própriounknownno 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 omodide CL, funcionam ali).Matches bywireValueor bylabel, case-insensitively, and excludesunknownitself 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'smodi, work there).Casa porwireValueo porlabel, sin distinguir mayúsculas, e ignora el propiounknownen 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 elmodide CL, funcionan ahí).
CommunicationType pílula do modal de comunicadocommunication modal pillpíldora del modal de comunicado 5
| case | value | Rótulo da pílulaPill labelRótulo de la píldora |
|---|---|---|
campaign | campaign | CampanhaCampaignCampaña |
promotion | promotion | PromoçãoPromotionPromoción |
news | news | NovidadeNewsNovedad |
operational | operational | OperacionalOperationalOperacional |
unknown | unknown | fallback 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é sempreinfoetagBackgroundColorsemprebrandAccent. O tipo muda apenas o texto.The pill colour doesn't vary by type:tagColoris alwaysinfoandtagBackgroundColoralwaysbrandAccent. The type only changes the text.El color de la píldora no varía por tipo:tagColores siempreinfoytagBackgroundColorsiemprebrandAccent. El tipo solo cambia el texto.
DataSourceType origem do fetchfetch originorigen del fetch 3
| case | Quem usa na HomeWho uses it on the HomeQuién lo usa en la Home |
|---|---|
mock | sessã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) |
local | build() 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 |
remote | default 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
| case | key | enabledMarkets | TTL |
|---|---|---|---|
homeKpi | homeKpi | BR · CL · ZA | 300 s |
communications | communications | BR · CL · ZA | 3600 s |
orders | orders | BR · CL · ZA | 600 s |
visits | visits | BR · CL · ZA | 600 s |
tasks | tasks | BR · CL · ZA | 600 s |
cases | cases | BR | — (cai no default 300 s)— (falls to the 300 s default)— (cae al default de 300 s) |
conectaVoce | conectaVoce | BR | — (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 singlecopyWith, 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 solocopyWith, 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).
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étodo | RetornaReturnsRetorna | UsoUseUso |
|---|---|---|
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étodo | RetornaReturnsRetorna | UsoUseUso |
|---|---|---|
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étodo | RetornaReturnsRetorna | UsoUseUso |
|---|---|---|
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 |
| CampoFieldCampo | Fonte (cache-only)Source (cache-only)Fuente (cache-only) | PredicadoPredicatePredicado |
|---|---|---|
pendingOrders | OrderRepository.getCachedOrders() | order.isPending — o grupo pending inteiro (8 status)the whole pending group (8 statuses)el grupo pending entero (8 estados) |
deliveries | GetDeliveriesOfTheDayUseCase.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 |
visitsOfTheDay | GetVisitsUseCase.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 |
cases | CaseManagementRepository.getCachedCases() | status ∈ {newCase, working, escalated, onHold}status ∈ {newCase, working, escalated, onHold}estado ∈ {newCase, working, escalated, onHold} |
conectaVoceActions | ConectaVoceApprovalsRepository.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 |
tasks | GetTasksUseCase.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 porsource: localcaem 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 explicitgetCached*methods, and the two going throughsource: localland 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étodosgetCached*explícitos, y las dos que pasan porsource: localcaen en la primera guard-clause del repository, que devuelve el caché sin tocar el remoto. RepActionsPendingCountsEntity- Seis campos
int, todos com default0, sem getters. Não tem modelo, DTO nem proto — é objeto de memória.Sixintfields, all defaulting to0, no getters. It has no model, DTO nor proto — it's an in-memory object.Seis camposint, todos con default0, 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étodo | RetornaReturnsRetorna | UsoUseUso |
|---|---|---|
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. |
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 / getter | TipoTypeTipo | Para quêWhat forPara qué |
|---|---|---|
visibleModules | List<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 |
marketName | String | nome do mercado ativo (não renderizado hoje)active market name (not rendered today)nombre del mercado activo (no renderizado hoy) |
environmentName | String | nome do ambiente (não renderizado hoje)environment name (not rendered today)nombre del ambiente (no renderizado hoy) |
resource | ResourceEntity? | 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 |
homeKpis | HomeKpiEntity? | o agregado de indicadores inteirothe whole indicator aggregateel agregado de indicadores entero |
communications | CommunicationsEntity? | o container de comunicados (não filtrado)the communications container (unfiltered)el contenedor de comunicados (no filtrado) |
repActionsCounts | RepActionsPendingCountsEntity | os 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 |
lastSyncAt | DateTime? | homeKpis?.lastSyncAt — a faixa do topo (§23)homeKpis?.lastSyncAt — the top strip (§23)homeKpis?.lastSyncAt — la franja superior (§23) |
endJourneyKpis | List<ActionKpiEntity> | KPIs da jornada — sem consumidor na Homejourney KPIs — no consumer on the HomeKPIs de la jornada — sin consumidor en la Home |
displayBullsEye | List<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 |
displayCommercialPillars | List<PillarKpiEntity> | idem, sobre commercialPillars.pillarsListsame, over commercialPillars.pillarsListídem, sobre commercialPillars.pillarsList |
displaySopCategories | List<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) |
displayVolumeOfTheDayCategories | List<BasicKpiEntity> | idem, zerando o que faltarsame, zeroing what's missingídem, poniendo en cero lo que falte |
displayDeliveryVolumeCategories | List<BasicKpiEntity> | idem, para o volume de entregasame, for delivery volumeídem, para el volumen de entrega |
displayVisitsOfTheDayDetails | List<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 |
displayOrdersOfTheDayDetails | List<DetailKpiEntity> | idem, para pedidos do diasame, for orders of the dayídem, para pedidos del día |
visibleCommunications | List<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 |
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 viaref.invalidate(homeProvider)estado error · retry víaref.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→ goToEndJourneygateend_journey→ goToEndJourneygateend_journey→ goToEndJourney
- EndJourneyPill gate
- CommunicationsCarouselModule gate
communications+ lista vaziagatecommunications+ empty listgatecommunications+ 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 orImage.network+ fallbackasset oImage.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"
- CommunicationImage asset ou
- CommunicationsCarouselIndicatorsWidget pontinhos · oculto com 1 itemdots · hidden with 1 itempuntitos · oculto con 1 ítem
- CommunicationBannerWidget banner tocáveltappable bannerbanner tocable
- CommunicationsCarouselWidget PageView · sem auto-avançono auto-advancesin auto-avance
- RepActionsModule ConsumerStatefulWidget · gate
rep_actions+ details vaziosgaterep_actions+ empty detailsgaterep_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 vaziagatebulls_eye+ empty listgatebulls_eye+ lista vacía- KpiHorizontalProgressRow uma por indicador declaradoone per declared indicatoruna por indicador declarado
- CommercialPillarsModule ConsumerWidget · gate
commercial_pillarsgatecommercial_pillarsgatecommercial_pillars- KpiHorizontalProgressRow uma por pilar · valores por
KpiValueFormatterone per pillar · values viaKpiValueFormatteruna por pilar · valores porKpiValueFormatter
- KpiHorizontalProgressRow uma por pilar · valores por
- VisitsOfTheDayModule ConsumerWidget · gate
visits_of_the_day+ KPI nulogatevisits_of_the_day+ null KPIgatevisits_of_the_day+ KPI nulo- KpiDonutCard detalhes só com
detailed· rótulo porVisitTypedetails only withdetailed· label viaVisitTypedetalles solo condetailed· rótulo porVisitType
- KpiDonutCard detalhes só com
- OrdersOfTheDayModule ConsumerWidget · gate
orders_of_the_day+ KPI nulogateorders_of_the_day+ null KPIgateorders_of_the_day+ KPI nulo- KpiDonutCard rótulo por
CategoryLabelResolver.shortlabel viaCategoryLabelResolver.shortrótulo porCategoryLabelResolver.short
- KpiDonutCard rótulo por
- VolumeOfTheDayModule StatefulWidget · gate
volume_of_the_day+ categorias vaziasgatevolume_of_the_day+ empty categoriesgatevolume_of_the_day+ categorías vacías- ExpandablePageView + KpiCarouselIndicator só com
carousele mais de 1 categoriaonly withcarouseland more than 1 categorysolo concarousely 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 ·
KpiModuleDetailListouCustomEmptyStateinfo-icon modal ·KpiModuleDetailListorCustomEmptyStatemodal del ícono de información ·KpiModuleDetailListoCustomEmptyState
- ExpandablePageView + KpiCarouselIndicator só com
- DeliveryVolumeOfTheDayModule StatefulWidget · gate
delivery_volume_of_the_day+ categorias vaziasgatedelivery_volume_of_the_day+ empty categoriesgatedelivery_volume_of_the_day+ categorías vacías- KpiModuleCard + KpiModuleHeader com seta de expandir quando
detailedwith expand arrow whendetailedcon flecha de expandir cuandodetailed - 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
- KpiModuleCard + KpiModuleHeader com seta de expandir quando
- CoverageModule ConsumerWidget · gate
vuse_coverage+modiCoveragenulogatevuse_coverage+ nullmodiCoveragegatevuse_coverage+modiCoveragenulo- KpiDonutCard com
expansionContentdas linhas de produtowith the product rows asexpansionContentconexpansionContentde las filas de producto - CoverageMissingRetailsModalContent ConsumerStatefulWidget · modal com abas por produto; observa
cachedRetailsBySfidProvidermodal with per-product tabs; watchescachedRetailsBySfidProvidermodal con pestañas por producto; observacachedRetailsBySfidProvider
- KpiDonutCard com
- SopModule StatefulWidget · gate
sop+ categorias vaziasgatesop+ empty categoriesgatesop+ categorías vacías- CustomDropdown<KpiTargetType> filtro de tipo, das
filterOptionstype filter, fromfilterOptionsfiltro de tipo, de lasfilterOptions - KpiLinearProgressBar · KpiSummaryRow uma seção por período das
periodOptionsone section per period fromperiodOptionsuna sección por período de lasperiodOptions - ExpandablePageView + KpiCarouselIndicator só com
carousele mais de 1 categoriaonly withcarouseland more than 1 categorysolo concarousely más de 1 categoría
- CustomDropdown<KpiTargetType> filtro de tipo, das
- DataLoadInfo
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).
Módulos da Home por mercadoHome modules by marketMódulos de la Home por mercado
| MóduloModuleMódulo | BR | CL | ZA |
|---|---|---|---|
end_journey | x | x | x |
communications | false | false | x |
rep_actions | x | x | x |
bulls_eye | — | — | x |
commercial_pillars | x | — | — |
visits_of_the_day | x | x | x |
orders_of_the_day | x | x | x |
volume_of_the_day | x | x | x |
delivery_volume_of_the_day | x | — | — |
vuse_coverage | — | x | — |
sop | x | — | x |
Atalhos (rep_actions.details) por mercadoShortcuts (rep_actions.details) by marketAtajos (rep_actions.details) por mercado
| AtalhoShortcutAtajo | BR | CL | ZA |
|---|---|---|---|
pending_orders | x | — | — |
deliveries_of_the_day | x | x | — |
cases | x | — | — |
tasks | x | — | x |
conecta_voce | x | — | — |
retails | x | x | x |
prime_simulator | x | — | — |
new_account | x | x | x |
returns_area | — | x | — |
collections_management | — | x | — |
clues | — | x | — |
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
| IndicadorIndicatorIndicador | FamíliaFamilyFamilia | BR | CL | ZA |
|---|---|---|---|---|
shipment_fmc | bulls_eye | — | — | x |
shipment_nc | bulls_eye | — | — | x |
target_fmc_soq | bulls_eye | — | — | x |
target_nc_soq | bulls_eye | — | — | x |
customer_execution | bulls_eye | — | — | x |
b2b_engagement | bulls_eye | — | — | x |
credit | bulls_eye | — | — | x |
overdue | commercial_pillars | x | — | — |
fat_partnership | commercial_pillars | x | — | — |
effectiveness | commercial_pillars | x | — | — |
prime_coverage | commercial_pillars | x | — | — |
productivity | commercial_pillars | x | — | — |
capilarity | commercial_pillars | x | — | — |
positivation_partnership | commercial_pillars | x | — | — |
boost_plan | commercial_pillars | x | — | — |
Formato dos cartões e opções por mercadoCard layouts and options by marketFormato de las tarjetas y opciones por mercado
| MóduloModuleMódulo | BR | CL | ZA |
|---|---|---|---|
communications | carousel | carousel | carousel |
visits_of_the_day | simple | detailed · physical_seller, physical_telesales, digital | detailed |
orders_of_the_day | simple | detailed · fmc, modi, ryo, partnership | detailed |
volume_of_the_day | carousel · fmc, partnership, otp | detailed, carousel · fmc, vuse, ryo, partnership | detailed, carousel · fmc, nc |
delivery_volume_of_the_day | carousel · fmc, partnership, otp | — | — |
vuse_coverage | — | product_images | — |
sop | carousel · fmc, partnership, otp · filtro delivered, all · períodos mtd, month | — | carousel · fmc, nc · filtro delivered, all · períodos mtd, month |
end_journey · rep_actions · bulls_eye · commercial_pillars | sem 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.
| ChaveKeyClave | TTL | Para que serve na HomeWhat it's for on the HomePara qué sirve en la Home |
|---|---|---|
homeKpi | 300 s | todos 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 |
communications | 3600 s | carrossel de comunicadoscommunications carouselcarrusel de comunicados |
orders | 600 s | contadores de pedidos pendentes e de entregas do diapending-orders and deliveries-of-the-day counterscontadores de pedidos pendientes y de entregas del día |
visits | 600 s | contador 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 |
tasks | 600 s | contador de tarefas pendentespending-tasks countercontador de tareas pendientes |
cases | não declarado → 300 sundeclared → 300 sno declarado → 300 s | contador de casos abertos (só BR)open-cases counter (BR only)contador de casos abiertos (solo BR) |
conectaVoce | não declarado → 300 sundeclared → 300 sno declarado → 300 s | contador de ações Conecta Você (só BR)Conecta Você actions counter (BR only)contador de acciones Conecta Você (solo BR) |
retails | 1800 s | nomes 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) |
notifications | 300 s | selo de não-lidas no sino da barraunread badge on the app-bar bellsello de no leídas en la campana de la barra |
resource | 3600 s | o 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 |
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.
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).
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.
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 comfalseem todo ohomeConfig, e ZA é o único mercado que o renderiza. Somando: não existem mocksbr_real_/cl_real_de comunicados (no modo real-mock esses mercados recebem{}), oza_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 withfalseanywhere inhomeConfig, and ZA is the only market rendering it. On top of that: there are nobr_real_/cl_real_communication mocks (in real-mock mode those markets get{}),za_real_communications.jsonis 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 confalseen todo elhomeConfig, y ZA es el único mercado que lo renderiza. Sumando: no existen mocksbr_real_/cl_real_de comunicados (en modo real-mock esos mercados reciben{}), elza_real_communications.jsones 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 declaravisits_of_the_daycomo detail derep_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.visitsOfTheDayis filled on every_load(), but no market declaresvisits_of_the_dayas arep_actionsdetail (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.visitsOfTheDayse llena en cada_load(), pero ningún mercado declaravisits_of_the_daycomo detail derep_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
pendinginteiro — os oito status do grupo, inclusivedraft,approvedeapprovedNotSync. 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 apendingRepApproval— 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 wholependinggroup — all eight statuses of the group, includingdraft,approvedandapprovedNotSync. 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 topendingRepApproval— 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 grupopendingentero — los ocho estados del grupo, incluidosdraft,approvedyapprovedNotSync. 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 apendingRepApproval— 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
lastSyncAtdos indicadores. O caminho de mock do repository de KPI é o único dos dois que não chama osave…— o de comunicados persiste. Consequência: em sessão mock o cache dehomeKpifica vazio, a faixa do topo mostra o timestamp cunhado em memória mas o sweep vêlastSyncAt == nulle 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 callsave…— the communications one persists. Consequence: in a mock session thehomeKpicache stays empty, the top strip shows the in-memory minted timestamp but the sweep seeslastSyncAt == nulland treats the type as stale on every cycle.El modo mock no puebla ellastSyncAtde los indicadores. El camino de mock del repository de KPI es el único de los dos que no llama alsave…— el de comunicados persiste. Consecuencia: en sesión mock el caché dehomeKpiqueda vacío, la franja superior muestra el timestamp acuñado en memoria pero el sweep velastSyncAt == nully 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.jsontraz um blocobullsEye— que BR não declara, logo é payload morto — e omite odeliveryVolumeOfTheDay, 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.jsoncarries abullsEyeblock — which BR doesn't declare, hence dead payload — and omitsdeliveryVolumeOfTheDay, 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. Elbr_real_home_kpi.jsontrae un bloquebullsEye— que BR no declara, o sea payload muerto — y omite eldeliveryVolumeOfTheDay, que BR sí declara: en modo real-mock la tarjeta de volumen de entrega aparece con todas las categorías en cero. caseseconectaVocenão têm TTL declarado emttlSecondsByType(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 porenabledMarkets, então esses dois tipos, declarados como BR-only, são varridos também em CL e ZA.casesandconectaVocehave no declared TTL inttlSecondsByType(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 byenabledMarkets, so those two types, declared BR-only, are swept in CL and ZA too.casesyconectaVoceno tienen TTL declarado enttlSecondsByType(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 porenabledMarkets, 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
deliveryVolumeOfTheDaye o caminho de carrossel usadeliveryVolumeTitle— o mesmo módulo muda de título conforme o formato declarado pelo mercado.Delivery volume has two titles. The single-card path uses thedeliveryVolumeOfTheDaykey and the carousel path usesdeliveryVolumeTitle— 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 clavedeliveryVolumeOfTheDayy el camino de carrusel usadeliveryVolumeTitle— 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 asfilterOptionsdo mercado, o módulo reatribui_selectedTypedentro do build, semsetState— funciona por acidente do ciclo de render, mas é a classe de código que quebra em rebuild fora de ordem.SOP mutates state insidebuild(). When the selected type isn't among the market'sfilterOptions, the module reassigns_selectedTypeinside build, with nosetState— 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 delbuild(). Cuando el tipo seleccionado no está entre lasfilterOptionsdel mercado, el módulo reasigna_selectedTypedentro del build, sinsetState— 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 inmenuConfig— 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 enmenuConfig— 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 aoCustomAppBar, 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ãosdisplayChatButtonedisplayChangeLocationButtonsão igualmente ignorados pela barra.The Home asks for a search button that doesn't exist. The page passesdisplaySearchButton: true, the shell forwards it toCustomAppBar, 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 siblingsdisplayChatButtonanddisplayChangeLocationButtonare equally ignored by the bar.La Home pide un botón de búsqueda que no existe. La page pasadisplaySearchButton: true, el shell lo reenvía alCustomAppBar, 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 hermanosdisplayChatButtonydisplayChangeLocationButtonson 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 declaramdateReferenceelastModifiedDatecomooptional: 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 declaredateReferenceandlastModifiedDateasoptional: 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 declarandateReferenceylastModifiedDatecomooptional: 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.dailyKpisnão aparece em nenhum EMC e o único método que ramifica nele —HomeNotifier.getModuleNameKey— não tem call site;ModuleDetailType.homeModuleChatBotVolltambé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 getterHomeState.endJourneyKpisnão tem leitor — a pílula de jornada só checa a presença do módulo, nunca os KPIs.Members with no consumer.ModuleType.dailyKpisappears in no EMC and the only method branching on it —HomeNotifier.getModuleNameKey— has no call site;ModuleDetailType.homeModuleChatBotVollisn't declared by any market either, so the "under development" notice branch is unreachable for it (onlyreturns_area, declared in CL, gets there); and theHomeState.endJourneyKpisgetter has no reader — the journey pill only checks module presence, never the KPIs.Miembros sin consumidor.ModuleType.dailyKpisno aparece en ningún EMC y el único método que ramifica en él —HomeNotifier.getModuleNameKey— no tiene call site;ModuleDetailType.homeModuleChatBotVolltampoco lo declara ningún mercado, así que el ramo de aviso "en desarrollo" es inalcanzable para él (soloreturns_area, declarado en CL, llega ahí); y el getterHomeState.endJourneyKpisno 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_coveragemas o indicador que ele lê chama-semodiCoverage— 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 asvuse_coveragebut the indicator it reads is namedmodiCoverage— 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 comovuse_coveragepero el indicador que lee se llamamodiCoverage— el cruce es deliberado y vive en el código del widget, pero obliga a quien lee la configuración a conocer el alias.