Como transformar uma planilha Gantt em um tracker de projetos que sua equipe pode consultar

Um gráfico de Gantt mostra o plano. Um banco de dados responde à pergunta que você realmente tem, que é o que atrasou e o que isso trava — e a coluna de dependências é onde a resposta está escondida.

As quatro perguntas que o cronograma importado responde em 9 de outubro de 2026: duas atividades atrasadas, duas em andamento, dois marcos à frente e três atividades bloqueadas porque dependem de algo atrasado

Tradução do original em inglês, testado em 9 de outubro de 2026. Código, números e datas são os do original. Read in English

Um gráfico de Gantt é muito bom em mostrar o plano e muito ruim em responder perguntas sobre ele. As barras são o ponto, e as barras também são o motivo de você acabar rastreando dependências com o dedo na tela.

A pergunta que você realmente tem numa segunda-feira é mais estreita: o que atrasou, e o que agora está preso atrás disso. Uma planilha mostra a primeira com formatação condicional. A segunda, ela faz você descobrir no olho.

Este guia move um cronograma de doze atividades para um banco de dados e faz as duas perguntas a ele. A importação levou 502 ms; as quatro queries de que um tracker precisa voltaram em menos de meio segundo cada.

Arquitetura: uma planilha Gantt vira uma classe Activity cujas datas são guardadas como datas e cujas dependências são um array, que quatro queries então leem para responder o que está atrasado, o que está rodando, quais marcos restam e o que está bloqueado

Como fica um cronograma depois que vira linhas?

Oito colunas, e só duas delas são interessantes. Uma linha de Gantt é uma atividade com início, fim e uma porcentagem; o que a torna um cronograma, e não uma lista, é a coluna que diz pelo que ela espera.

id  name                   owner           start       end         progress  dependsOn  milestone
5   Import pipeline        Tomas Vidal     2026-09-22  2026-10-03  80                4  false
6   Permissions and roles  Nadia Okonkwo   2026-09-28  2026-10-07  45                4  false
9   Beta with two teams    Nadia Okonkwo   2026-10-12  2026-10-24   0              6,7  true

dependsOn é a coluna que as pessoas deixam de fora quando movem uma planilha para uma ferramenta, porque o gráfico desenha as setas por elas. Perca essa coluna e você fica com a imagem e joga fora a única coisa que responde “e daí?”.

Quais tipos de coluna importam de verdade?

Dois: as datas precisam ser datas, e as dependências precisam ser um array. Todo o resto pode ser o que for mais conveniente.

// Stack: Node 22 | File: import-and-query.mjs
{
  activityId: { type: 'Number' },
  name:       { type: 'String' },
  owner:      { type: 'String' },
  start:      { type: 'Date' },      // not String
  end:        { type: 'Date' },      // not String
  progress:   { type: 'Number' },
  dependsOn:  { type: 'Array' },     // not a comma-separated String
  milestone:  { type: 'Boolean' },
}

Datas como texto parecem bem até você compará-las. 2026-10-9 e 2026-10-09 são strings diferentes, ordenam de forma diferente, e nenhuma das duas se compara corretamente com uma data de verdade — então “o que está atrasado” devolve silenciosamente as linhas erradas em vez de falhar.

Dependências como texto têm o mesmo tipo de problema. "6,7" não pode ser pesquisado por pertencimento; como array, pode, e essa é toda a segunda metade deste post.

Como medimos: a classe foi criada com um POST /schemas/Activity e devolveu HTTP 200 em 3,1 segundos, reportando de volta os oito campos mais os quatro que o Parse acrescenta.

Como colocar doze linhas de uma vez?

Com uma requisição batch, não com doze idas e voltas. O endpoint de batch recebe uma lista de operações e as executa no servidor:

await fetch(`${PARSE}/batch`, {
  method: 'POST', headers: asServer,
  body: JSON.stringify({
    requests: rows.map((body) => ({ method: 'POST', path: '/classes/Activity', body })),
  }),
});

Isso importou todas as doze em 502 ms. Doze requisições separadas da mesma máquina custariam doze idas e voltas; esta custa uma.

Como medimos: um POST /batch carregando doze operações de criação, cronometrado em torno da chamada única, devolvendo doze objetos de sucesso.

O que está atrasado, e o que isso bloqueia?

Duas queries, e a segunda é a que uma planilha não faz por você. Atrasado é uma interseção direta — a data de fim passou e o trabalho não terminou:

{ "end": { "$lt": { "__type": "Date", "iso": "2026-10-09T00:00:00.000Z" } },
  "progress": { "$lt": 100 } }

Em 9 de outubro, isso devolveu duas atividades: o pipeline de importação com 80% e as permissões com 45%. Quatro outras atividades tinham data de fim no passado e foram corretamente deixadas de fora, porque estavam concluídas.

Depois, a pergunta que o gráfico faz você rastrear à mão. Pegue os ids das atividades atrasadas e pergunte quais linhas dependem de qualquer uma delas:

{ "dependsOn": { "$in": [5, 6] } }

Três atividades voltaram — a dashboard de relatórios, o beta e a revisão de segurança. Duas tarefas que atrasaram estão segurando três outras, e ninguém precisou seguir uma seta para descobrir.

O gráfico mostra a dependência. O array deixa você fazer uma pergunta a ela.

O que mais um tracker precisa responder?

Mais duas queries, as duas de uma linha, e junto com as duas primeiras elas cobrem a reunião de segunda-feira:

PerguntaA queryEm 9 de out
O que está atrasado?end < today e progress < 1002 — 466 ms
O que está rodando agora?start <= today <= end2 — 278 ms
Quais marcos restam?milestone = true e end >= today2 — 168 ms
O que está bloqueado?dependsOn $in [late ids]3 — 170 ms

Como medimos: cada query cronometrada individualmente contra a classe importada, já aquecida, de um laptop para a região USA East. A primeira é mais lenta porque é a primeira — a conexão está fria.

Essas respostas estão certas?

Estão, e vale conferir em vez de presumir. As mesmas quatro perguntas foram recalculadas a partir do CSV original em Python, sem nenhum banco de dados envolvido:

                  from the database      from the spreadsheet
late              2  [5, 6]              2  [5, 6]
in flight         2  [7, 8]              2  [7, 8]
milestones ahead  2  [9, 12]             2  [9, 12]
blocked           3  [8, 9, 10]          3  [8, 9, 10]

Idênticas, incluindo os ids exatos das atividades. A linha interessante é a terceira: um marco de aprovação da arquitetura em 16 de setembro está corretamente ausente das duas, porque ficou para trás — uma query que contasse todos os marcos teria dito três, e seria inútil.

Como medimos: o verify.py do repositório companion lê activities.csv e aplica as mesmas quatro regras em Python puro; os números do banco vêm da execução acima.

Quais erros você vai encontrar ao importar um cronograma?

Três, e o primeiro é o que custa uma tarde.

O que você vêO que significa
{"code":107,"error":"cannot route POST /parse/classes/Activity"}o caminho do batch carrega um prefixo /parse que não deveria
As datas importam, mas $lt devolve tudo ou nadaa coluna é String; recrie como Date e importe de novo
Queries em dependsOn não devolvem nada com $ina coluna é uma String como "6,7", não um array

Nenhum dos três é um erro de validação, e é isso que os torna lentos de achar: a importação tem sucesso, os dados parecem certos no Database Browser, e só as queries se comportam de forma estranha. Se uma comparação de datas devolve um número que você não consegue explicar, verifique o tipo da coluna antes de verificar a query.

Quando a planilha ainda é a ferramenta melhor?

Enquanto o plano ainda está mudando de forma. Arrastar uma barra é mais rápido que uma migração, e um cronograma que ainda está em discussão não se beneficia de um schema — a folga é o recurso.

Também não há problema em ficar na planilha quando ninguém mais a lê. O caso para migrar é várias pessoas fazendo perguntas diferentes ao mesmo plano ao mesmo tempo; para uma pessoa com uma visão só, o gráfico já é a resposta.

E se o que você precisa é a imagem, e não as perguntas, fique com o gráfico. Nada aqui desenha um Gantt — responde a queries sobre um. Um tracker que não consegue mostrar as barras vai perder para uma planilha que consegue, por melhor que seja o seu modelo de dados.

O que você acrescentaria ao tracker de cronograma em seguida?

Um par de datas baseline ao lado das datas vivas. Toda linha aqui tem um início e um fim, o que significa que o cronograma pode atrasar sem deixar rastro do que foi prometido — e “estamos atrasados?” é uma pergunta diferente de “isso algum dia teve chance?”.

Depois disso, a cadeia de dependências em vez de um salto só. A query de bloqueio encontra o que espera diretamente por uma tarefa atrasada; ela não segue a cadeia até a data de lançamento três passos adiante. Isso é uma função de Cloud Code percorrendo dependsOn recursivamente, e é o ponto em que o tracker começa a dizer algo que a planilha nunca conseguiria.

Tagsspreadsheetproject-managementganttparse-serverrest-apidata-modeling

Perguntas frequentes

Como transformar uma planilha Gantt em um banco de dados?

Uma classe, uma linha por atividade, e datas guardadas como datas em vez de texto. Crie a classe com activityId, name, owner, start, end, progress, dependsOn e milestone, depois envie as linhas em uma única requisição batch. Em 9 de outubro de 2026, doze atividades entraram juntas em 502 ms, depois de a classe ser criada em 3,1 segundos.

Como consultar quais tarefas estão atrasadas?

Peça as linhas cuja data de fim já passou e cujo progresso está abaixo de 100, em uma query: where end menor que hoje e progress menor que 100. Guardar as datas como tipo Date em vez de string é o que faz a comparação funcionar — como texto, 2026-10-9 e 2026-10-09 ordenam de forma diferente e nenhuma se compara corretamente com uma data de verdade.

Como descobrir o que uma tarefa atrasada está bloqueando?

Mantenha as dependências como um array de ids de atividade e consulte com o operador $in. Com a lista de ids atrasados em mãos, uma query pelas linhas cujo array dependsOn contém qualquer um deles devolve tudo o que está a jusante. Na execução medida, duas atividades atrasadas bloquearam três outras, que é o número que uma planilha faz você descobrir no olho.

Qual é o caminho do endpoint de batch no Back4app?

Os caminhos dentro de uma requisição batch começam em /classes, não em /parse/classes. Boa parte da documentação do Parse mostra a forma longa porque um Parse Server auto-hospedado costuma ficar montado em /parse; em parseapi.back4app.com esse prefixo devolve o erro 107, cannot route POST /parse/classes/Activity. Tire o prefixo e o mesmo batch tem sucesso.

Um agente de IA deve construir o app ou você deve modelar por conta própria?

Os dois, nessa ordem, é a resposta honesta. Um agente é rápido em transformar uma planilha em uma interface funcional, e o formato dos dados que ele produz é com o que você vai conviver depois. Saber de quais colunas o cronograma realmente precisa — datas como datas, dependências como array — significa que você pode conferir o trabalho do agente em vez de herdá-lo.

Leitura complementar

Revisado e verificado por Back4app Engineering, Editorial review na Back4app

Testado em 9 de outubro de 2026 — Backend: Back4app, plano Free, USA East · Fonte: uma planilha de 12 atividades com dependências · Terminal: node e curl no macOS.

Mais da Back4app Engineering

Agente de IA · tutorial

How to Turn a Spreadsheet Into a Web App With a Database and Login

Backend · tutorial

Como encontrar o motorista mais próximo em um app estilo Uber

Agente de IA · tutorial

How to Build an Inventory Management System Without Writing Code