Comando: cat projects/project-office.md
PMO de produto e projetos, com edição simultânea sem perda
Sistema interno para gerir produto, projetos e pessoas: Scrum e Kanban com sprints, backlog priorizado, burndown e velocity, carga por pessoa, dossiê de cada projeto, mapa mental e uma visão executiva. Várias pessoas editam o mesmo projeto ao mesmo tempo sem que uma apague o trabalho da outra, e cada projeto só chega a quem tem permissão, conferida no servidor em toda requisição.
abrir demonstraçãosimulação do sistema com dados fictícios · 6 telas
- Papel
- Único engenheiro, do produto à operação
- Período
- jul/2026 – set/2026
- O que eu fiz
Eu: Produto, arquitetura, backend na borda sem Node, modelo de dados, sincronização e fusão de edições, segurança do login, todas as telas e os testes.
Projeto privado, descrito sem identificar cliente, produto ou empresa.
Diagrama
No navegador, a SPA React salva cada projeto levando a versão que conhece e, periodicamente, checa só a versão atual. O Worker, feito só com Web APIs e sem Node, confere a lista de acesso do projeto em toda requisição e protege o login com PBKDF2 e uma verificação anti-robô que falha fechada; grava no D1 com prepared statements e guarda os arquivos no KV, fora do banco. Se alguém salvou antes, o Worker responde conflito, e o navegador faz a fusão de três vias e reenvia depois de uma espera aleatória.
Contexto
O grupo precisava de um lugar só para gerir produto, projetos e pessoas: sprints, backlog, prazos, a carga de cada um e o porquê das decisões, com várias pessoas mexendo no mesmo quadro ao mesmo tempo.
O que eu construí
- Execução. Quadro Kanban com arrastar e soltar, e também mover por seleção, para quem usa teclado; sprints com meta e datas; backlog por MoSCoW com pontos Fibonacci; e um dashboard com burndown, velocity, distribuição de tarefas e próximos prazos.
- Pessoas & Desempenho. Carga contra capacidade, cycle time, throughput de 14 dias e risco de atraso, calculados a partir das tarefas de cada pessoa.
- Conhecimento. O dossiê de cada projeto (visão, modelo de negócio, OKRs, riscos e decisões), um mapa mental em canvas infinito com organização automática, documentos com visualização no próprio app e um diretório de ferramentas por setor.
- Visão executiva. Um consolidado por período, por projeto e por pessoa, que soma a mesma pessoa entre projetos pelo e-mail.
- Colaboração sem perda. Salvamento automático com versão, fusão item a item quando há conflito e as mudanças da equipe aparecendo sozinhas na tela.
O que eu faria diferente
Colocaria o teste de carga com vários editores junto da primeira versão da fusão. O livelock só apareceu quando oito editores salvaram ao mesmo tempo, e a espera aleatória que veio depois poderia ter nascido junto com o tratamento de conflito.
Restrições
- Várias pessoas editando o mesmo projeto ao mesmo tempo, sem perder trabalho.
- Cada pessoa vê só os projetos liberados para ela, e quem garante isso é o servidor.
- Backend no runtime de borda, sem Node e sem ORM.
- Uma única pessoa técnica para construir e operar.
Decisões
Concorrência otimista com fusão de três vias
- Contexto
- Cada projeto é salvo como um documento. Com duas pessoas editando, quem salvasse por último apagaria a mudança da outra sem aviso.
- Escolha
- Cada salvamento leva a versão que o navegador conhece. Se alguém salvou antes, o servidor responde conflito, e o navegador junta base, versão local e versão do servidor item a item (tarefa, sprint, bloco do mapa) e reenvia depois de uma espera aleatória.
- Ganhos
- Conflito vira fusão, e não sobrescrita.
- A espera aleatória veio de um livelock medido num teste de carga com oito editores.
- Custos
- A fusão precisa conhecer cada tipo de item do documento; um tipo novo pede regra nova.
Sincronização por checagem leve de versão
- Contexto
- Conexões persistentes trariam mais infraestrutura para um time pequeno, com poucos editores ao mesmo tempo.
- Escolha
- A cada 4 segundos, com variação aleatória, o navegador pergunta só a versão do projeto, e pausa quando a aba está escondida. Os índices do banco foram criados para esse caminho.
- Ganhos
- Simples e barato, sem conexão aberta.
- Custos
- A mudança de outra pessoa pode levar alguns segundos para aparecer.
- Tráfego constante, ainda que leve, enquanto a aba está aberta.
Permissão por projeto no servidor, em toda requisição
- Contexto
- Esconder um projeto na tela não impede um membro de pedi-lo direto à API.
- Escolha
- Uma lista de acesso usuário × projeto conferida em toda requisição; administradores veem tudo, com salvaguardas para que um administrador não se tranque para fora.
- Ganhos
- Quem não está na lista do projeto não recebe o projeto do servidor.
- Custos
- Toda rota nova precisa aplicar a checagem, o que pede disciplina e um teste a cada rota.
Login que falha fechado
- Contexto
- Força bruta e robôs são o risco mais óbvio de um sistema na internet, e uma configuração esquecida não pode abrir a porta.
- Escolha
- PBKDF2 com 100 mil iterações, comparação em tempo constante e o mesmo custo para e-mail inexistente, bloqueio atômico por conta, limite por IP em tabela própria e verificação anti-robô que bloqueia o login quando o segredo não está configurado.
- Ganhos
- Uma configuração ausente bloqueia, em vez de liberar em silêncio.
- Custos
- Um deploy mal configurado tranca todo mundo para fora até ser corrigido.
Stack e por quê
- React 18 e Vite
- Aplicação de página única servida pelo próprio Worker.
- Cloudflare Workers, D1 e KV
- Backend em Web APIs do runtime, SQL com prepared statements e arquivos fora do banco.
- Recharts e React Flow
- Burndown, velocity e distribuição; mapa mental em canvas infinito.
- WebCrypto e Turnstile
- PBKDF2 sem dependência e verificação anti-robô que falha fechada.
- Vitest
- Rotas do Worker, segurança, fusão e estado testados no CI.
Resultados
23 arquivos de teste com cerca de 220 casos, cobrindo rotas do Worker, segurança, fusão de edições e estado, rodando no CI.
repositório privado auditadoTestes e workflow de CI do repositório(Auditoria do repositório privado, set/2026)Uma tabela de rotas única, com um teste que falha se algum handler ficar de fora.
repositório privado auditadoCódigo do Worker e testes(Auditoria do repositório privado, set/2026)Uma rodada de correção de 19 itens de segurança e de integridade de dados, todos fechados com testes.
declaradoRegistro de correções do projeto
Ângulo de segurança
Superfície de ataque
- Login com senha e verificação anti-robô.
- API de projetos, documentos e usuários.
- Upload e visualização de documentos no próprio app.
- Edição simultânea do mesmo projeto.
Controles implementados
- PBKDF2 com 100 mil iterações, comparação em tempo constante e o mesmo custo para e-mail inexistente.
- Bloqueio atômico por conta e limite de tentativas por IP.
- Verificação anti-robô e checagem de origem que falham fechadas.
- Lista de acesso por projeto conferida em toda requisição.
- Upload por lista permitida, sem executáveis, e arquivos servidos com política restritiva.
- Links aceitos só em http e https.
O que eu testaria hoje
- Um membro pedindo pela API um projeto que não foi liberado para ele.
- Dois editores salvando o mesmo item no mesmo instante.
- Uma mutação enviada de outra origem.
Evidências
- repositório privado auditadoRepositório privado auditado(Auditoria do repositório privado, set/2026)