Skip to content

app ​

Tipo
Referência
Para
Desenvolvedor, Analista

Um app é uma Aplicação do DataViz. O arquivo apps/<slug>--<id>.yaml guarda tudo dela: tabelas, relacionamentos, expressões, indicadores, filtros de abertura e os Dashboards com os Widgets. Não há arquivo separado de Dashboard; cada item de dashboards: segue a referência de app-dashboard.

Os conceitos ficam nas suítes: modelo de dados e relacionamentos, linguagem de expressões, filtros e indicadores.

Crie com lumo new app --name "Comercial". Para os ids de coluna usados em indicadores, filtros e Widgets, rode lumo info app:<id> --full.

Campos ​

  • fileName
    string · opcional · valores: regex ^[a-z0-9-]+--\d+\.yaml$
  • header
    object · obrigatório
  • header.id
    integer · obrigatório · valores: ≥ 1
  • header.kind
    string · obrigatório · valores: app (fixo)
  • header.lumo
    string · obrigatório · valores: v2 (fixo)
  • header.tenantId
    integer · obrigatório · valores: ≥ 1
  • header.appId
    integer · opcional · valores: ≥ 1
  • header.dashboardId
    integer · opcional · valores: ≥ 1
  • body
    object · obrigatório
  • body.criado_em
    string ou null · opcional · valores: regex ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$
    Somente leitura: o servidor preenche.
  • body.criado_por
    string ou integer ou null · opcional
    Somente leitura: o servidor preenche.
  • body.publicado_em
    string ou null · opcional · valores: regex ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$
    Somente leitura: o servidor preenche.
  • body.publicado_por
    string ou integer ou null · opcional
    Somente leitura: o servidor preenche.
  • body.nome
    string · obrigatório · valores: não vazio
  • body._state
    string · opcional · valores: draft, published, inconsistent
    Somente leitura: o servidor preenche. Derived lifecycle state. draft=deskId null (work-in-progress, owner-only). published=deskId set (live, readonly, shared). inconsistent=domain invariant violated (e.g. published flow ↔ draft table); treat as 'stop and ask'. Server-computed; edits are ignored on push.
  • body.descricao
    string ou null · opcional
  • body.icon
    string ou null · opcional
  • body.color
    string ou null · opcional · valores: regex ^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$
  • body.deskId
    integer ou null · opcional · valores: ≥ 1
    Somente leitura: o servidor preenche. Server-managed publish state; change through publish commands, not declarative push.
  • body.version
    integer ou null · opcional · valores: ≥ 0
    Somente leitura: o servidor preenche. Server-managed resource version.
  • body.config
    object · obrigatório
  • body.config.show_last_loadedat
    boolean · opcional
  • body.config.show_last_loadedat_tables
    array de integer · opcional
  • body.config.tables
    object · opcional
  • body.filtros
    array · opcional
    Lista de filtro de inicialização do modo 'default' (um conjunto para a aplicação inteira). Só lida/gravada quando filter_mode é 'default' - no modo 'per_dashboard' cada aba declara a própria lista em dashboards[].body.filters (shared.schema.json#/$defs/filterDefinition; mesmo conceito de dado desta lista, que fica em jsonValue por compatibilidade com o que já circula em produção).
  • body.filter_mode
    string ou null · opcional · valores: default, per_dashboard
    'default' (ou ausente/null) = um conjunto de filtro para a aplicação inteira (filtros acima + allow_new_filters abaixo). 'per_dashboard' = cada dashboard declara o próprio conjunto (dashboards[].body.filters/allow_new_filters). null = app nunca configurou - equivale a 'default', e é o que o CLI emite para todo app que nunca usou o recurso (hash de drift descarta chave null).
  • body.allow_new_filters
    boolean ou null · opcional
    Modo 'default': se quem usa o app pode adicionar filtro além da lista declarada em filtros. null = herda o padrão (true); só false explícito bloqueia. Sem efeito no modo 'per_dashboard' (cada aba tem o seu próprio, em dashboards[].body.allow_new_filters).
  • body.tables
    array de object · opcional
  • body.tables[].tableId
    integer · obrigatório · valores: ≥ 1
  • body.tables[].guid
    string ou null · opcional
  • body.tables[].nome_visualizacao
    string ou null · opcional
    Per-app display rename ('nome de visualização' set in the DataViz table editor). SEMANTICALLY SIGNIFICANT: when set, expression and dataSource references must address the table by THIS name - [<nome_visualizacao>]."COL" - not the physical DW table name. Omit (or null) to keep the physical name. Setting it here renames the table for THIS app only; omitting it on push clears a previous rename (file-first).
  • body.tables[].tipo
    string ou null · opcional · valores: dimension, n2n
    App-table role. 'dimension' (default) is just a label and covers every normal table; fact and dimension are not types, they come from how the relations are drawn: a fact is a table no relation leaves from (it is only ever to_table_id) or a table that is the N side of a relation whose N-side column is a date (a sales header joined to the calendar by its issue date); a dimension is a table that is the 1 side (from_table_id) of some relation; one table can be both. Only 'n2n' changes the engine: it marks a bridge table, crossed also from the 1 side to the N side (needs relationships from at least two tables pointing to it, lint warns otherwise). Do NOT use 'fact'/'dim'/'bridge' - server rejects.
  • body.tables[].appTableId
    integer ou null · opcional · valores: ≥ 1
  • body.tables[].columns
    object · opcional
    App-scoped per-column overlay (the DataViz 'Configurar Campos' / 'Visibilidade das Colunas'). Keyed by column_name; only columns that DIFFER from the default appear. visible: false hides the column from the END-USER report generator / field picker - the column stays fully usable in expressions and widgets (declutter, NOT access control). label overrides the column's display name for THIS app only (other apps and the DW table are unaffected). Omit a table's columns to leave its overlay untouched; {} clears every override. Draft apps only.
  • body.tables[].columns.<chave>.visible
    boolean · opcional
  • body.tables[].columns.<chave>.label
    string ou null · opcional
  • body.expressions
    array de object · opcional
  • body.expressions[].human_description
    string ou null · opcional
    Obsoleto. Nome antigo, ainda aceito; use description. Descrição BREVE da expressão, no máximo 150 caracteres - o mesmo limite que o editor de expressões do DataViz impõe a quem digita. A tela de Expressões mostra essa frase inteira, numa linha só e sem reticências, para o usuário ler de relance; passando disso a coluna estica e empurra os botões da linha para fora da tela. Documentação longa vai em documentation, que não tem limite e não é renderizada na lista.
  • body.expressions[].description
    string ou null · opcional
    Descrição BREVE da expressão, escrita para a IA ler (o que ela mede, sobre qual base), no máximo 150 caracteres: o limite do editor de expressões do DataViz. Gravado como human_description. Documentação longa vai em documentation.
  • body.expressions[].type
    string · opcional · valores: sql, dax
    Linguagem da fórmula em expression. Ausente = mantém a da expressão salva (sql na expressão nova). dax só para medida (data_type Number, behavior measure) e pede a feature flag habilitar-dax de quem cria ou edita; o push valida a fórmula e recusa com linha e coluna. Exemplos: lumo scaffold expression dax. Referência: https://docs.horusbi.com.br/dataviz/construir/dax/referencia-rapida
  • body.relationships
    array de object · opcional
  • body.relationships[].id
    integer · opcional · valores: ≥ 1
  • body.relationships[].column_left_id
    integer · obrigatório: em uma das alternativas · valores: ≥ 1
  • body.relationships[].column_right_id
    integer · obrigatório: em uma das alternativas · valores: ≥ 1
  • body.relationships[].from_column
    string · obrigatório: em uma das alternativas
  • body.relationships[].from_table_id
    integer · obrigatório · valores: ≥ 1
  • body.relationships[].to_column
    string · obrigatório: em uma das alternativas
  • body.relationships[].to_table_id
    integer · obrigatório · valores: ≥ 1
  • body.relationships[].relationshipType
    string · opcional · valores: ONE_TO_ONE, ONE_TO_MANY, MANY_TO_ONE, MANY_TO_MANY
    ONE_TO_ONE is honored by lumo push: the server stores the row as ONE_TO_ONE and the engine walks it in both directions, so the key must be unique on BOTH sides (push warns with RELATIONSHIP_KEY_REPEATS when it is not). Any other value has no effect: the row is ONE_TO_MANY and the direction comes from which table is from_table_id (the '1' side) and which is to_table_id.
  • body.relationships[].ignoreTime
    boolean · opcional
  • body.indicators
    array de object · opcional
    Indicadores da app: a definição oficial de cada número (métrica + filtro fixo + coluna de data), que o cockpit, a Lumia, o MCP e o Sentinela consomem. Outro filtro ou outra data é outro indicador. Ver lumo scaffold indicator.
  • body.indicators[].id
    integer · opcional · valores: ≥ 1
  • body.indicators[].nome
    string · obrigatório · valores: não vazio
    O nome que a pessoa fala: "Aprovado", "Faturamento". Dois indicadores com o mesmo nome e contas diferentes confundem a IA e o cockpit.
  • body.indicators[].primaryColumn
    string · obrigatório · valores: regex ^X?\d+(:[A-Za-z0-9_]+)+$
    A métrica do indicador: "<colunaId>:AGG" (SUM, COUNT, AVG, MIN, MAX, DISTINCT) ou uma expressão da app, "X<id>:EXPR".
  • body.indicators[].alternativeColumns
    array de string ou null · opcional
    Outras métricas com o MESMO filtro e a MESMA data (contagem, ticket). Com outro filtro ou outra data, crie outro indicador.
  • body.indicators[].dateColumnId
    integer ou null · opcional · valores: ≥ 1
    A coluna de data que dá sentido ao período (data de aprovação, de emissão, de pagamento). Outra data é outro indicador.
  • body.indicators[].defaultDatePeriod
    string ou null · opcional · valores: Today, CurrentMonth, MonthToDate, PreviousMonth, Yesterday, CurrentYear, NextYear, DayBeforeYesterday, AllTime, PreviousYear, ThisWeek, PreviousWeek, NextWeek, Last7Days
  • body.indicators[].filters
    array · opcional
    Filtro fixo que faz parte da definição (ex.: status aprovado). É ele que poupa a IA de descobrir coluna e valores a cada pergunta. Outro filtro é outro indicador.
  • body.indicators[].prompt
    string ou null · opcional
    Obsoleto.
  • body.indicators[].description
    string ou null · opcional
    Descrição do indicador, lida pela IA (prompt no banco).
  • body.indicators[].apresentacao
    object · opcional
    Apresentação no cockpit. Bloco ausente preserva; bloco presente é estado desejado. Nada aqui afeta a resposta da IA.
  • body.indicators[].apresentacao.icone
    string ou null · opcional
  • body.indicators[].apresentacao.cor
    string ou null · opcional
  • body.indicators[].apresentacao.formato
    string ou null · opcional · valores: currency, percent, integer, decimal
  • body.indicators[].apresentacao.direcao
    string ou null · opcional · valores: up_good, down_good, neutral
  • body.indicators[].monitoramento
    object · opcional
    Grão, janela e farol. Mesma semântica de bloco de apresentacao.
  • body.indicators[].monitoramento.grao
    string ou null · opcional · valores: hour, day, week, month
  • body.indicators[].monitoramento.janelaDias
    integer ou null · opcional · valores: ≥ 1, ≤ 1095
  • body.indicators[].monitoramento.farol
    string ou object · opcional · valores: auto
  • body.indicators[].monitoramento.farol.verde
    number · obrigatório
  • body.indicators[].monitoramento.farol.ambar
    number · obrigatório
  • body.indicators[].principal
    boolean · opcional
    Indicador principal do tenant (destaque no cockpit). Ausente preserva o valor do servidor.
  • body.indicators[].meta
    - · opcional
    Obsoleto. Ignorado pelo servidor (o valor não é lido nem gravado). O lint avisa; remova a chave.
  • body.facts
    array de object · opcional
    Obsoleto. Nome antigo de indicators (mesma lista). Aceito com aviso; o pull grava indicators.
  • body.facts[].id
    integer · opcional · valores: ≥ 1
  • body.facts[].nome
    string · obrigatório · valores: não vazio
    O nome que a pessoa fala: "Aprovado", "Faturamento". Dois indicadores com o mesmo nome e contas diferentes confundem a IA e o cockpit.
  • body.facts[].primaryColumn
    string · obrigatório · valores: regex ^X?\d+(:[A-Za-z0-9_]+)+$
    A métrica do indicador: "<colunaId>:AGG" (SUM, COUNT, AVG, MIN, MAX, DISTINCT) ou uma expressão da app, "X<id>:EXPR".
  • body.facts[].alternativeColumns
    array de string ou null · opcional
    Outras métricas com o MESMO filtro e a MESMA data (contagem, ticket). Com outro filtro ou outra data, crie outro indicador.
  • body.facts[].dateColumnId
    integer ou null · opcional · valores: ≥ 1
    A coluna de data que dá sentido ao período (data de aprovação, de emissão, de pagamento). Outra data é outro indicador.
  • body.facts[].defaultDatePeriod
    string ou null · opcional · valores: Today, CurrentMonth, MonthToDate, PreviousMonth, Yesterday, CurrentYear, NextYear, DayBeforeYesterday, AllTime, PreviousYear, ThisWeek, PreviousWeek, NextWeek, Last7Days
  • body.facts[].filters
    array · opcional
    Filtro fixo que faz parte da definição (ex.: status aprovado). É ele que poupa a IA de descobrir coluna e valores a cada pergunta. Outro filtro é outro indicador.
  • body.facts[].prompt
    string ou null · opcional
    Obsoleto.
  • body.facts[].description
    string ou null · opcional
    Descrição do indicador, lida pela IA (prompt no banco).
  • body.facts[].apresentacao
    object · opcional
    Apresentação no cockpit. Bloco ausente preserva; bloco presente é estado desejado. Nada aqui afeta a resposta da IA.
  • body.facts[].apresentacao.icone
    string ou null · opcional
  • body.facts[].apresentacao.cor
    string ou null · opcional
  • body.facts[].apresentacao.formato
    string ou null · opcional · valores: currency, percent, integer, decimal
  • body.facts[].apresentacao.direcao
    string ou null · opcional · valores: up_good, down_good, neutral
  • body.facts[].monitoramento
    object · opcional
    Grão, janela e farol. Mesma semântica de bloco de apresentacao.
  • body.facts[].monitoramento.grao
    string ou null · opcional · valores: hour, day, week, month
  • body.facts[].monitoramento.janelaDias
    integer ou null · opcional · valores: ≥ 1, ≤ 1095
  • body.facts[].monitoramento.farol
    string ou object · opcional · valores: auto
  • body.facts[].monitoramento.farol.verde
    number · obrigatório
  • body.facts[].monitoramento.farol.ambar
    number · obrigatório
  • body.facts[].principal
    boolean · opcional
    Indicador principal do tenant (destaque no cockpit). Ausente preserva o valor do servidor.
  • body.facts[].meta
    - · opcional
    Obsoleto. Ignorado pelo servidor (o valor não é lido nem gravado). O lint avisa; remova a chave.
  • body.reports
    array de object · opcional
    Relatórios PUBLICADOS do app (bi_app_bookmark type=report, status=curated). Pessoal e filtro salvo ficam fora. Ausente = preserva o servidor; [] apaga todos; item que sai da lista é apagado. Ver lumo scaffold report.
  • body.reports[].internalId
    string ou null · opcional
    Identidade do relatório. Ausente = cria um novo; o push grava o id gerado de volta no arquivo.
  • body.reports[].name
    string · obrigatório · valores: não vazio
  • body.reports[].description
    string ou null · opcional
  • body.reports[].columns
    array de string · obrigatório
  • body.reports[].filter
    array de object · opcional
  • body.reports[].filter[].column
    object · obrigatório
  • body.reports[].filter[].column.column_id
    string ou integer · obrigatório
    Normalmente inteiro; dado real em circulação às vezes serializa como string numérica (ex.: YAML pré-existente) - aceito nas duas formas.
  • body.reports[].filter[].column.expression
    string ou null · opcional
  • body.reports[].filter[].operator
    string ou null · opcional
  • body.reports[].filter[].value
    qualquer valor · opcional
    false é o marcador de campo declarado vazio (vaga): a aba assume a coluna como filtrável mas sem valor próprio, e herda o que estava aplicado na aba anterior. Qualquer outro valor (inclusive array, para múltipla escolha) é o valor efetivamente aplicado.
  • body.reports[].filter[].comparativeValues
    qualquer valor · opcional
  • body.reports[].filter[].required
    integer ou null · opcional · valores: 0, 1, 2, 3
    0 = opcional, múltiplos valores (padrão). 1 = obrigatório, um ou mais valores. 2 = obrigatório, valor único. 3 = opcional, valor único.
  • body.reports[].filter[].mergeStrategy
    string ou null · opcional
  • body.reports[].filter[].ask_on_open
    boolean · opcional
    Pergunta o valor ao abrir o relatório; o valor salvo vira false.
  • body.reports[].filter[].hint
    string ou null · opcional
    Texto de ajuda da pergunta.
  • body.reports[].sort
    array de object · opcional
  • body.reports[].sort[].column_id
    string ou integer · obrigatório
  • body.reports[].sort[].expression
    string · obrigatório
  • body.reports[].sort[].direction
    string · obrigatório · valores: ASC, DESC
  • body.reports[].breaks
    array de object · opcional
  • body.reports[].breaks[].column_id
    string ou integer · obrigatório
  • body.reports[].breaks[].expression
    string · obrigatório
  • body.reports[].matrixAxis
    object ou null · opcional
  • body.reports[].matrixAxis.column_id
    string ou integer · obrigatório
  • body.reports[].matrixAxis.expression
    string · obrigatório
  • body.reports[].scenarios
    integer · opcional · valores: ≥ 1
  • body.dynamic_dimensions
    array · opcional
  • body.tags
    array de string · opcional
  • body.dashboards
    array de object · opcional
  • body.dashboards[].header
    object · opcional
    Every field, including id, is optional here: lumo push fills id:0 (create) plus kind/lumo/tenantId/appId from the app's own header before sending. header: {} and an absent header key are the same intent.
  • body.dashboards[].header.id
    integer · opcional · valores: ≥ 0
    A dashboard header id. 0 means "create a new dashboard" on push; a positive value addresses an existing one. Kept separate from #/$defs/id (minimum 1) because 0 is a valid, meaningful value here and nowhere else.
  • body.dashboards[].header.kind
    string · opcional · valores: app-dashboard (fixo)
  • body.dashboards[].header.lumo
    string · opcional · valores: v2 (fixo)
  • body.dashboards[].header.tenantId
    integer · opcional · valores: ≥ 1
  • body.dashboards[].header.appId
    integer · opcional · valores: ≥ 1
  • body.dashboards[].body
    object · obrigatório
  • body.dashboards[].body.criado_em
    string ou null · opcional · valores: regex ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$
    Somente leitura: o servidor preenche.
  • body.dashboards[].body.criado_por
    string ou integer ou null · opcional
    Somente leitura: o servidor preenche.
  • body.dashboards[].body.publicado_em
    string ou null · opcional · valores: regex ^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$
    Somente leitura: o servidor preenche.
  • body.dashboards[].body.publicado_por
    string ou integer ou null · opcional
    Somente leitura: o servidor preenche.
  • body.dashboards[].body.nome
    string · obrigatório · valores: não vazio
  • body.dashboards[].body.ordem
    integer · opcional · valores: ≥ 0
  • body.dashboards[].body.widget_columns
    integer · opcional · valores: ≥ 1
  • body.dashboards[].body.widget_float
    boolean · opcional
  • body.dashboards[].body.version
    integer ou null · opcional · valores: ≥ 0
    Somente leitura: o servidor preenche. Server-managed resource version.
  • body.dashboards[].body.filters
    array de object ou null · opcional
    Filtros de inicialização desta aba, só relevantes quando o app está em modo 'per_dashboard' (body.filter_mode do app). null (ou chave ausente) = aba nunca configurou filtro próprio - equivale a [] com allow_new_filters liberado, e é o que o CLI emite para toda aba que nunca usou o recurso (o hash de drift descarta chave null, então essa aba não muda de hash entre versões do CLI). Ver shared.schema.json#/$defs/filterDefinition para o contrato de cada item, inclusive value: false como campo declarado vazio.
  • body.dashboards[].body.filters[].column
    object · obrigatório
  • body.dashboards[].body.filters[].column.column_id
    string ou integer · obrigatório
    Normalmente inteiro; dado real em circulação às vezes serializa como string numérica (ex.: YAML pré-existente) - aceito nas duas formas.
  • body.dashboards[].body.filters[].column.expression
    string ou null · opcional
  • body.dashboards[].body.filters[].operator
    string ou null · opcional
  • body.dashboards[].body.filters[].value
    qualquer valor · opcional
    false é o marcador de campo declarado vazio (vaga): a aba assume a coluna como filtrável mas sem valor próprio, e herda o que estava aplicado na aba anterior. Qualquer outro valor (inclusive array, para múltipla escolha) é o valor efetivamente aplicado.
  • body.dashboards[].body.filters[].comparativeValues
    qualquer valor · opcional
  • body.dashboards[].body.filters[].required
    integer ou null · opcional · valores: 0, 1, 2, 3
    0 = opcional, múltiplos valores (padrão). 1 = obrigatório, um ou mais valores. 2 = obrigatório, valor único. 3 = opcional, valor único.
  • body.dashboards[].body.filters[].mergeStrategy
    string ou null · opcional
  • body.dashboards[].body.allow_new_filters
    boolean ou null · opcional
    Se quem usa a aba pode adicionar filtro além da lista declarada em filters. null = herda o padrão (true); só false explícito bloqueia.
  • body.dashboards[].body.widgets
    array de object · opcional
    Optional: an absent key means a brand-new, still-empty tab (the server defaults it to [] too). Create it, fill in widgets on a later push.
  • body.dashboards[].body.widgets[].id
    integer · opcional · valores: ≥ 1
  • body.dashboards[].body.widgets[].guid
    string · opcional · valores: não vazio
  • body.dashboards[].body.widgets[].nome
    string · opcional
  • body.dashboards[].body.widgets[].type
    string · obrigatório · valores: Kpi, Barline, Pie, Table, Matrix, ComposedMatrix, Map, Gauge, Punchcard, Sankey, Forecast, Calendar, ListBox, Text, Diagram, Svelte, ParametricSvelte, App
  • body.dashboards[].body.widgets[].display_nome
    boolean · opcional
  • body.dashboards[].body.widgets[].x
    number · obrigatório
  • body.dashboards[].body.widgets[].y
    number · obrigatório
  • body.dashboards[].body.widgets[].w
    number ou null · opcional · valores: > 0
  • body.dashboards[].body.widgets[].h
    number ou null · opcional · valores: > 0
  • body.dashboards[].body.widgets[].mobileY
    number · opcional
  • body.dashboards[].body.widgets[].mobileH
    number · opcional · valores: > 0
  • body.dashboards[].body.widgets[].mobileVisible
    boolean · opcional
  • body.dashboards[].body.widgets[].chart
    object · opcional

Exemplo ​

yaml
# apps/comercial--7302.yaml
# yaml-language-server: $schema=https://docs.horusbi.com.br/schemas/v2/app.schema.json
id: 7302
kind: app
lumo: v2
tenantId: 1200
---
nome: Comercial
descricao: Vendas por filial e período.
icon: mdi:chart-bar
color: "#3B82F6"
config: {}
tables:
  - tableId: 6230            # fato_vendas
    tipo: dimension          # vale para tabela fato e dimensão; n2n só em tabela ponte
  - tableId: 6105            # dim_filiais
    tipo: dimension
relationships:
  - from_table_id: 6105      # lado "1": a chave não se repete
    to_table_id: 6230        # lado "N"
    from_column: ID_FILIAL
    to_column: FILIAL_ID
indicators:
  - nome: Faturamento
    primaryColumn: "70011:SUM"     # coluna VALOR_TOTAL, somada (lumo info app:7302 --full)
    dateColumnId: 70012            # DATA_EMISSAO
    defaultDatePeriod: CurrentMonth
    description: Soma do valor dos pedidos, pela data de emissão.
filtros:
  - column: { column_id: "70012", expression: "DATE" }
    operator: RELATIVE
    value: currentMonth
dashboards:
  - header:
      id: 0                  # 0 = criar no próximo push; mantenha o id dos que já existem
    body:
      nome: Visão geral
      ordem: 0
      widget_columns: 12
      widgets:
        - nome: Faturamento
          type: Kpi
          w: 3
          h: 1
          x: 0
          y: 0
          chart:
            primaryData:
              dataSource: "70011:SUM"
              title:
                value: Faturamento
              filter: []

Limites ​

  • indicators é o nome atual da lista de indicadores. O nome antigo, facts, ainda é aceito com aviso do lint, e o pull grava indicators. Um arquivo com as duas chaves é recusado. No indicador, description substitui o antigo prompt.
  • expressions (expressões calculadas) tem o formato comentado em lumo scaffold app, na seção EXPRESSIONS. O esquema não detalha os campos de cada expressão, então o lint não os confere.
  • relationshipType: só ONE_TO_ONE muda algo, e exige chave única dos dois lados. Qualquer outro valor vira um-para-muitos, com o lado "1" em from_table_id e o lado "N" em to_table_id. Se a chave do lado "1" se repete, o push avisa (RELATIONSHIP_KEY_REPEATS); lumo info app:<id> --key-check lista as relações que já estão assim.
  • Dois relacionamentos entre as mesmas duas tabelas: vale o primeiro da lista. A ordem do array é gravada a cada push, então reordenar troca qual relacionamento manda. Para usar o outro numa expressão só, use use() na expressão.
  • Data com data: em relacionamento entre duas colunas de data, ponha ignoreTime: true, ou a hora impede o filtro de passar.
  • tipo aceita dimension (toda tabela comum, fato ou dimensão) e n2n (tabela ponte de muitos-para-muitos). O servidor recusa outro valor.
  • nome_visualizacao renomeia a tabela só nesta Aplicação, e expressões e Widgets passam a usar o nome novo. Tirar a chave desfaz o nome no próximo push.
  • columns dentro de tables[] com visible: false só esconde a coluna do gerador de relatórios. Ela continua usável em expressões e Widgets: isso arruma a tela e não restringe acesso.
  • dashboards: substitui a lista inteira. Um Dashboard que está no servidor e falta no array é apagado. Edite no lugar e mantenha o header.id de cada um.
  • filtros só vale com filter_mode ausente ou default. Com filter_mode: per_dashboard, cada Dashboard usa o próprio filters.
  • Publicada, a Aplicação aceita push só em nome, descricao, icon, color, indicators, reports, filtros, filter_mode e allow_new_filters, e no filters/allow_new_filters de cada Dashboard. O resto pede lumo app clone e lumo app publish.
  • Publicar exige que as tabelas da Aplicação já estejam publicadas.
  • monitoramento.farol manual pede verde menor que ambar, e o lint não confere a ordem. Um monitoramento sem farol mantém o farol gravado.