Skip to Content

Ambiente local

Pré-requisitos

  • Node.js 18+
  • Docker + Docker Compose
  • npm

Subir a infraestrutura

docker compose up -d postgres redis

PostgreSQL em localhost:5432, Redis em localhost:6379.

Para desenvolver contra SQL Server em vez de Postgres:

docker compose -f docker-compose.test.yml --profile mssql up -d mssql

e configure a API com DB_TYPE=mssql (ver cms-api/src/app.module.ts).

Iniciar a API

cd cms-api npm install npm run start:dev

A API sobe em http://localhost:3000/api.

Na primeira execução o módulo seed cria automaticamente:

  • perfil Administrador
  • usuário admin — admin@cms.local, com senha aleatória impressa no log da primeira inicialização da API (procure o bloco Usuário administrador criado). A senha nasce expirada: o primeiro acesso obriga a trocá-la antes de abrir qualquer tela.
  • catálogo de Ferramentas (menus e permissões)

Iniciar o frontend

cd cms-frontend npm install npm run dev

Frontend em http://localhost:3001. Login: admin@cms.local, com a senha que apareceu no log da API na primeira execução — ela não é exibida de novo, e precisa ser trocada no primeiro acesso.

Iniciar a documentação (opcional)

cd cms-docs npm install npm run dev

Documentação em http://localhost:3002/docs.

Variáveis de ambiente

# As senhas abaixo são as do .env da raiz, que ./scripts/instalar.sh gera na primeira execução. # Não existe valor de exemplo que funcione: a checagem de boot recusa subir com segredo publicado # (ver cms-api/src/common/validar-segredos-boot.ts), e isso inclui a senha dentro da DATABASE_URL. DATABASE_URL=postgres://cms:<POSTGRES_PASSWORD do .env>@localhost:5432/cms REDIS_URL=redis://:<REDIS_PASSWORD do .env>@localhost:6379 JWT_SECRET=<openssl rand -hex 32> JWT_EXPIRES_IN=8h APP_PORT=3000 APP_URL=http://localhost:3000 CORS_ORIGIN=http://localhost:3001 WORKER_CONCURRENCY=100 DB_POOL_MAX=70 HTTP_BACKLOG=1024 SMTP_HOST=smtp.gmail.com SMTP_PORT=587 SMTP_USER= SMTP_PASS= SMTP_FROM=noreply@cms.local

Para SQL Server, troque DATABASE_URL por DB_TYPE=mssql + MSSQL_HOST, MSSQL_PORT (padrão 1433), MSSQL_USER, MSSQL_PASSWORD, MSSQL_DATABASE, MSSQL_ENCRYPT e MSSQL_TRUST_SERVER_CERTIFICATE.

Em desenvolvimento, os conectores SAP (cms-sap-connector, cms-idoc-connector) sobem com o stub local: não é preciso ter o SAP NW RFC SDK instalado para rodar o resto do sistema. Para falar com um SAP de verdade, instale o SDK e defina SAP_RFC_CLIENT=real — veja SAP RFC / BAPI.

Serviços e portas

ServiçoPortaObservação
cms-api3000NestJS
cms-frontend3001Next.js
cms-docs3002Nextra (esta documentação)
cms-sap-connector4000Publicada no host porque em dev o cms-api roda nativo no Windows
cms-idoc-connector—Só na rede interna do compose
PostgreSQL5432
Redis6379
Nginx80 / 443Só no compose completo · HTTP/2 no vhost do aplicativo

Ambiente de teste (sistemas externos)

Os bancos e o broker usados para exercitar os conectores não estão no docker-compose.yml: eles vivem num projeto Docker separado, o industry-test, descrito pelo docker-compose.test.yml. Na visão do CMS eles são sistemas do cliente — não fazem parte da stack que é instalada.

docker compose -f docker-compose.test.yml up -d # tudo, menos o SQL Server docker compose -f docker-compose.test.yml --profile mssql up -d # + SQL Server (~1 GB) docker compose -f docker-compose.test.yml down # derruba só o ambiente de teste
ServiçoPorta publicadaEndereço na Conexão ExternaAcesso
TimescaleDB (Postgres externo)5433host.docker.internal:5433cms / TIMESCALE_PASSWORD, banco cms_timeseries
InfluxDB8086http://host.docker.internal:8086org cms, token INFLUX_TOKEN
MongoDB (replica set rs0)27017mongodb://host.docker.internal:27017/?directConnection=truecms / MONGO_PASSWORD
Mosquitto (MQTT)18830host.docker.internal:18830sem autenticação
SQL Server — profile mssql1433host.docker.internal:1433sa / MSSQL_SA_PASSWORD
Oracle XE (~2 GB de RAM)1521host.docker.internal:1521, service XEPDB1system / ORACLE_PASSWORD

A porta é sempre a publicada (a coluna do meio), inclusive onde ela difere da interna: o Mosquitto atende em 1883 dentro da rede do Docker e em 18830 aqui fora, o TimescaleDB em 5432 e 5433. E o host é host.docker.internal, não o nome do serviço: é o único nome que o cms-api alcança nos dois modos de execução — em container e rodando nativo na máquina, sem Docker. Uma Conexão gravada como mongo:27017 só funciona no primeiro.

Conexões de Arquivo e SQLite têm a mesma incompatibilidade, num campo diferente: elas guardam um caminho (/data/arquivos/...), que existe dentro do container porque o compose monta ./data/arquivos ali. Rodando nativo no Windows, o Node resolve /data/arquivos para <drive atual>:\data\arquivos — que não existe, e o sintoma é a Aplicação parada em OFF com “directory does not exist”.

Uma junction faz o mesmo caminho valer nos dois modos, sem tocar no cadastro das Conexões (ajuste o drive para o do seu clone):

mklink /J X:\data X:\cms\data

Não precisa de administrador. Vale saber o efeito colateral enquanto a origem está OFF: o agendador PULA a Coleta sem consumir tentativa (ver coletarOrigens), então uma mensagem daquela Definição já em AGUARDANDO_REENVIO fica parada até a Aplicação voltar. É o gate de Keep Alive funcionando, não uma fila travada — mas ela conta como “Em Processamento” no monitor enquanto isso.

Os nomes em maiúsculas são variáveis do .env da raiz, geradas por ./scripts/instalar.sh. Até 2026-09-01 esta tabela publicava os valores, e o docker-compose.test.yml os trazia como default — o que parecia inofensivo (na época estes containers publicavam só em 127.0.0.1, e não vão para instalação de cliente) até a auditoria mostrar o caminho real do problema: valor de senha escrito no repositório circula, e o que nasce como default de QA reaparece em instalação de verdade. Por isso nenhuma senha aparece nesta tabela, e validar-segredos-boot.ts recusa a subida da API com qualquer valor de exemplo conhecido.

Trocar uma dessas senhas depois do primeiro start não muda o banco: Postgres, Mongo e Influx gravam a senha no volume, na inicialização. Ou rode o ALTER USER equivalente dentro do container, ou descarte o volume — são bancos descartáveis: docker compose -f docker-compose.test.yml down -v.

Os containers entram na rede cms-network, que é criada pelo docker-compose.yml — suba a stack principal pelo menos uma vez antes, senão o Compose reclama que a rede externa não existe. E eles não têm política de restart: reiniciar a máquina não os traz de volta, é preciso rodar o up -d de novo.

Ferramentas de Help Desk

As ferramentas de chamado (Help Desk) ficam num terceiro projeto Docker, o industry-helpdesk, descrito pelo docker-compose.helpdesk.yml. Os dois simulam sistemas do cliente, com papéis diferentes: o industry-test são as fontes de dados que os conectores leem e escrevem; este são os canais de escalonamento de um alerta. Quem mexe num conector de banco não precisa do GLPI de pé, e derrubar os bancos não leva a ferramenta de chamados junto.

docker compose -f docker-compose.helpdesk.yml up -d # sobe o grupo Help Desk docker compose -f docker-compose.helpdesk.yml down # derruba só ele (os volumes ficam)
ServiçoPorta publicadaURL base na ativaçãoAcesso
GLPI8380http://host.docker.internal:8380/apirest.phpglpi / glpi no primeiro acesso; banco com GLPI_DB_PASSWORD

Valem as mesmas regras de rede e endereço do ambiente de teste: cms-network criada antes, e host.docker.internal com a porta publicada.

O GLPI pede três passos manuais depois do primeiro start, uma vez só (ficam no volume): ligar a API com login por credencial, tirar a restrição de IP do cliente de API e ligar os fusos horários com o fuso padrão da instância. Os comandos estão no cabeçalho do docker-compose.helpdesk.yml. Sem o terceiro, a hora de abertura dos chamados aparece adiantada — e quem já estava logado precisa sair e entrar de novo para ver a hora certa.

As outras ferramentas do catálogo (ServiceNow, Jira SM, Freshservice, Zendesk, InvGate) são SaaS e não têm imagem Docker. Para elas valem as contas gratuitas: a instância de desenvolvedor (PDI) do ServiceNow, o plano Free do Jira SM e os trials das demais.