◧
RedmineProjetos, épicos, tarefas, subtarefas, horas, Gantt, wiki≈ Jira Software + Tempo
▤
Quadro KanbanDrag-and-drop, drawer com comentários e anexos, filtros≈ quadro do Jira
◈
GLPI Service DeskPortal do cliente, SLA, e-mail→ticket, base de conhecimento≈ Jira Service Management
▦
PlannerCalendário de alocação: o coordenador planeja, o dev vê e confirma≈ Tempo Planner
↔
Ciclo completoChamado GLPI #4 ↔ issue #28 com comentários e anexosdemo real executada
O que já roda de verdade
Nada aqui é maquete — cada linha foi executada neste ambiente.
| Capacidade | Evidência | |
|---|---|---|
| Hierarquia épico → tarefa → subtarefa | Épico FSWTBC-4991 (5 tarefas) e FSWTBC-4620 (15 subtarefas) importados do Jira real via API, com status e link de volta | pronto |
| Quadro kanban | Autentica pela sessão do Redmine (ninguém digita chave), move status por drag-and-drop, drawer lê comentários e anexos | pronto |
| Portal do cliente | Usuário cliente.fujioka abriu o chamado pelo portal self-service do GLPI, com anexo | pronto |
| Comentários bidirecionais | Comentário do cliente virou nota na issue; resposta da engenharia voltou como followup no chamado | pronto |
| Anexos bidirecionais | erro-pdv-se1.txt (cliente → engenharia) e analise-tecnica-fuj028.txt (engenharia → cliente) | pronto |
| Status sincronizado | Issue movida para Em Homologação no Redmine → chamado do cliente foi para Pendente automaticamente | pronto |
| Identidade visual | Tema TBC com as cores oficiais da TOTVS (#753399, do design system PO-UI), interface em pt-BR | pronto |
| Planner (alocação) | Calendário pessoa × dia: o coordenador aloca, o dev vê só o que é dele e confirma ou recusa. Mostra carga da semana e avisa quando passa da jornada | pronto |
| Apontamento de horas | Nativo do Redmine (time_entries) + custom fields — mesma modelagem do vínculo Tempo↔PSA de hoje | a validar |
| Ponte com o PSA | Sincronizar time_entries com o Dynamics; é do que o faturamento depende | go/no-go |
O ciclo que rodou
Chamado #4 do cliente Fujioka, do portal até a devolutiva — sem ninguém copiar nada entre sistemas.
sequenceDiagram
autonumber
actor C as Cliente (portal)
participant G as GLPI
participant P as Ponte (2 min)
participant R as Redmine
actor T as Time TBC
C->>G: Abre chamado + anexa log do erro
P->>R: Cria issue #28 com descrição e anexo
P->>G: Confirma registro com link da issue
C->>G: Comenta "aconteceu em 14 vendas"
P->>R: Vira comentário na issue
T->>R: Responde, anexa análise técnica
T->>R: Move para Em Homologação (no quadro)
P->>G: Publica resposta + anexo no chamado
P->>G: Chamado passa para Pendente
G-->>C: Cliente vê tudo no portal
Arquitetura
flowchart LR
subgraph vps [vps_4 Hostinger · Docker]
GLPI[GLPI 11
portal · SLA · e-mail→ticket · KB]
RM[Redmine 6.1
projetos · horas · wiki · Gantt]
BOARD[Quadro Kanban
SPA sobre a REST API]
HUB[tbc_sync
ponte + automações]
end
CLIENTE((Clientes)) -->|portal · e-mail| GLPI
TIME((Time TBC)) --> RM & BOARD
GLPI <-->|REST API| HUB
HUB <-->|REST API| RM
HUB -.->|a construir| PSA[(Dynamics 365 PSA
faturamento)]
JIRA[(Jira Cloud)] -.->|importador API→API| RM
Como a ponte foi feita
Sem plugin, sem fornecedor: um script Python de ~200 linhas em /root/redmine-mvp/tbc_sync.py, cron a cada 2 minutos.
| Opção | Latência | Situação |
|---|---|---|
| Poller REST — consulta as duas APIs e concilia por id (à prova de eco: a ponte registra o que ela mesma escreve) | até 2 min | em uso |
| Webhook nativo do GLPI — dispara na hora do evento | segundos | próximo |
Micro-plugin no Redmine — ~50 linhas Ruby, after_save → webhook (tempo real na volta) | segundos | fase 2 |
| Motor de automação — regras YAML (gatilho → condição → ação): SLA, auto-resposta, transições, aviso no chat | — | fase 2 |
Segurança — o que foi atacado e corrigido
Um agente revisor com contexto zerado tentou quebrar o ambiente. O que ele achou virou correção.
| Achado | Correção | |
|---|---|---|
XSS no quadro kanban — o título da tarefa era injetado via innerHTML; um assunto com <img onerror> executava script no navegador de quem abrisse o quadro | Quadro reescrito: todo dado de usuário entra por textContent. Reteste com o mesmo payload confirma que agora vira texto escapado | corrigido |
Auto-registro aberto — qualquer pessoa na internet criava conta no Redmine em /register | Auto-registro desabilitado (/register devolve 404) e login passou a ser obrigatório (anônimo é redirecionado) | corrigido |
Contas padrão do GLPI (tech, normal, post-only) e senha glpi/glpi | Contas desativadas e senha trocada — as quatro combinações padrão foram testadas e todas falham | corrigido |
| Sem backup | Backup diário às 03:17: dump dos dois bancos + volumes, retenção de 7 dias. Restauração testada: os dumps foram restaurados em bancos descartáveis e conferidos (24 issues e 2 projetos no Redmine; 1 chamado, 6 usuários e 5 documentos no GLPI; 1.050 arquivos no volume) | corrigido |
| Sem HSTS e segredos legíveis por outros usuários do host | HSTS ativo nos dois domínios; .env e sync.env em modo 600 | corrigido |
| Superfície exposta | Verificado de fora: só 80/443 respondem. Portas de aplicação e de banco (8090, 8091, 5433, 6380, 3306) estão fechadas. Certificado renova sozinho pelo timer do certbot | confirmado |
O que ainda não está pronto
Honestidade importa mais que demo bonita.
| Pendência | Impacto |
|---|---|
| Ponte de horas com o PSA (Dynamics) | É o go/no-go do projeto: o fechamento mensal depende dela. Precisa rodar em paralelo ao Tempo por um ciclo inteiro antes de qualquer corte. |
| SLA configurado no GLPI | O GLPI tem SLA nativo, mas ainda não parametrizamos as regras da TBC. |
| E-mail → ticket | Nativo nos dois; falta apontar a caixa postal e testar com um cliente real. |
| Importação completa do Jira | Importamos 1 épico + 20 issues para provar o caminho. Faltam as 6.400 restantes, automações, dashboards e filtros salvos. |
| Backup fora da vps_4 | Hoje o backup mora no mesmo servidor que ele protege. Se a VPS morrer, morre junto — falta enviar para o Drive ou outra VPS. |