T ToutadminDocumentação

Instalar a edição Node

A edição Node corre como um serviço permanente: um processo, uma base SQLite no disco, nada mais para instalar — nem base de dados externa, nem cache, nem fila. Este tutorial vai da pasta vazia à instância em produção, incluindo o que a maioria dos guias deixa de fora: o serviço do sistema, o proxy inverso, o TLS, as cópias de segurança e a atualização.

O que é preciso#

ElementoVersãoPorquê
Node.js22 ou mais recenteO produto apoia-se no seu executor de testes integrado e em APIs recentes.
Um compilador Cbuild-essentialO better-sqlite3 compila-se na instalação, salvo se existir um binário pronto para a sua plataforma.
Um disco localO SQLite e os ficheiros depositados. Nunca uma partilha de rede: veja mais abaixo.

Uma máquina de um núcleo e 512 MB de memória chega para algumas dezenas de pessoas. O que conta não é a potência mas o disco: tem de ser local e ter cópia de segurança.

1. Obter e instalar#

git clone <o-seu-repositório> /var/www/toutadmin
cd /var/www/toutadmin
npm ci --omit=dev

npm ci em vez de npm install: instala exatamente o que o ficheiro de bloqueio descreve, sem nunca o reescrever. Num servidor, uma versão que escorrega é uma avaria que ninguém percebe.

Se a compilação falhar

O better-sqlite3 é a única dependência que compila C. sudo apt install -y build-essential python3 resolve a quase totalidade dos casos.

2. Configurar#

cp .env.example .env

Tudo se define por variáveis de ambiente — lidas de .env, ou postas pelo seu gestor de serviços. Nenhuma é obrigatória: sem .env, a instância arranca na porta 3000 e envia-o ao assistente.

VariávelPredefiniçãoO que faz
PORT3000A porta de escuta.
NODE_ENVproduction em produção: cookies estritos, sem rastos detalhados.
SESSION_SECRETgeradoSela as sessões. Deixado vazio, é gerado em data/session.key.
INSTALL_TOKENReclamado pelo assistente antes de instalar. Recomendado num servidor exposto.
TRUST_PROXY1 atrás de um proxy de confiança, e só aí.
DB_PATHdata/app.sqliteA base.
UPLOAD_DIR, CV_DIR, VAULT_DIR, SIGN_DIR, DOCS_DIR, BACKUP_DIRsob data/As pastas de ficheiros: fotografias, currículos, cofre, livro de assinaturas, documentos recebidos, arquivos.
LOGIN_RATE_LIMIT10Tentativas de acesso por quarto de hora e por endereço.
GLOBAL_RATE_LIMIT300Pedidos por minuto e por endereço.
API_RATE_LIMITChamadas de API por minuto e por token.
SESSION_IDLE_MINUTES60Inatividade a partir da qual a sessão cai.
SESSION_MAX_HOURS12Duração absoluta que nenhuma atividade prolonga.
ADMIN_EMAIL, ADMIN_PASSWORDInstalação sem interface: cria o administrador no arranque.
O segredo de sessão

Mudar SESSION_SECRET desliga toda a gente de uma vez. Ponha-o uma vez, gere-o ao acaso (node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"), e guarde-o com o resto. Nunca o deixe num repositório git.

Pôr um símbolo de instalação#

Entre o primeiro arranque e a sua passagem pelo assistente, a instância é de quem a encontrar: o primeiro a chegar cria a conta de administração. Ponha, pois, INSTALL_TOKEN antes de abrir a porta:

node -e "console.log(require('crypto').randomBytes(16).toString('hex'))"
# depois em .env:
INSTALL_TOKEN=c3f1…

O assistente compara-o em tempo constante — uma comparação vulgar deixaria adivinhar o símbolo carácter a carácter — e regista cada recusa. Uma vez instalada a instância, o assistente fecha-se sozinho.

Instalar sem interface#

Para uma implantação automatizada, ADMIN_EMAIL e ADMIN_PASSWORD criam o administrador no arranque, sem passar pelo assistente. Retire-os depois: uma palavra-passe no ambiente de um serviço é lida por quem lê esse serviço.

3. Permissões e onde vivem os dados#

sudo useradd --system --home /var/www/toutadmin --shell /usr/sbin/nologin toutadmin
sudo chown -R toutadmin:toutadmin /var/www/toutadmin/data
sudo chmod 750 /var/www/toutadmin/data
sudo chmod 640 /var/www/toutadmin/.env

O código pode ficar apenas de leitura; só data/ tem de ser gravável. O SQLite escreve ficheiros vizinhos (-wal, -shm): o que conta é a pasta, não apenas a base.

Nunca numa partilha de rede

NFS e SMB mentem quanto ao bloqueio de ficheiros. O SQLite conta com esse bloqueio para impedir duas escritas em simultâneo: numa partilha, a base acaba por se corromper sem avisar. Disco local, sempre — e é a cópia de segurança que parte para outro lado, não a base.

4. O serviço#

Lançado à mão, o produto para quando fecha o terminal. Confie-o ao systemd:

# /etc/systemd/system/toutadmin.service
[Unit]
Description=Toutadmin
After=network.target

[Service]
Type=simple
User=toutadmin
WorkingDirectory=/var/www/toutadmin
EnvironmentFile=/var/www/toutadmin/.env
ExecStart=/usr/bin/node src/server.js
Restart=always
RestartSec=5

# O serviço só precisa de escrever em data/.
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/www/toutadmin/data

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now toutadmin
sudo systemctl status toutadmin
journalctl -u toutadmin -f

As cinco linhas de endurecimento não são decorativas: ProtectSystem=strict torna todo o sistema de ficheiros não gravável, e ReadWritePaths reabre a única pasta que o tem de ser. Uma falha de escrita arbitrária atinge então apenas data/.

5. O proxy inverso#

Nunca sirva a porta 3000 diretamente na internet: não faz TLS e não tem razão para aprender a fazê-lo.

server {
    listen 443 ssl http2;
    server_name intranet.exemplo.pt;

    ssl_certificate     /etc/letsencrypt/live/intranet.exemplo.pt/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/intranet.exemplo.pt/privkey.pem;

    client_max_body_size 20M;          # depósitos no cofre, documentos recebidos

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

server {
    listen 80;
    server_name intranet.exemplo.pt;
    return 301 https://$host$request_uri;
}

Faça também com que o serviço escute apenas no anel local, para que a porta 3000 só seja alcançável pelo proxy.

TLS#

sudo certbot --nginx -d intranet.exemplo.pt

O produto põe o cabeçalho Strict-Transport-Security assim que a ligação está cifrada, e nunca em claro: anunciado a partir de uma página não cifrada não seria lido, e prenderia um ensaio local em https durante seis meses.

O TRUST_PROXY anda com o proxy, e só com ele

Esta variável faz o servidor acreditar no endereço de origem anunciado num cabeçalho. Atrás do nginx é o que é preciso: senão todos os pedidos parecem vir de 127.0.0.1 e os limites por endereço deixam de proteger seja o que for. Sem proxy à frente é o contrário: qualquer um anuncia o endereço que quiser e contorna os limites.

6. O assistente#

Abra o seu domínio. Enquanto não existir conta nenhuma, todo o endereço reencaminha para /installation. Cinco passos:

  1. O idioma da instância, entre os 16.
  2. Os pré-requisitos, verificados e mostrados.
  3. A empresa: o nome mostrado em toda a parte.
  4. As férias anuais atribuídas a cada novo trabalhador não independente.
  5. A conta de administração: endereço e palavra-passe de pelo menos doze caracteres.

Logo que exista uma conta, /installation reencaminha para a página de acesso: o assistente fechou-se sozinho, não há ficheiro nenhum para apagar à mão.

7. A varredura periódica#

Ao contrário da edição PHP, não há nada a agendar: o servidor traz o seu próprio agendador, que acorda de hora a hora e faz oito coisas.

O que a varredura fazGarantia
Fecha as contas cujo contrato chegou ao fimVerificado também no acesso e ao abrir o painel
Emite as faturas das subscrições vencidasUm índice único impede faturar duas vezes
Transforma os prazos em notificaçõesUma chave de desduplicação: um prazo avisa uma vez
Limpa as notificações lidas e o registo de auditoriaConforme a conservação escolhida
Recolhe a caixa de correio contabilística (IMAP)Se a recolha estiver configurada
Esvazia a fila dos webhooks, com as suas repetiçõesCinco tentativas, depois desistência
Cria a cópia automática e externaliza-aQuando o intervalo decorreu

Cada operação é idempotente: uma varredura repetida não fatura duas vezes nem notifica duas vezes. É isso que permite reiniciar o serviço a qualquer momento sem pensar nisso.

8. Verificar que tudo funciona#

# os testes (não escrevem na sua base)
npm test

# uma instância de demonstração, para dar uma volta
node scripts/seed-demo.js

Depois, na interface: crie um membro, entre com ele, deposite um anexo, lance uma cópia manual e verifique-a no ecrã Cópias de segurança. Estes quatro gestos tocam na base, nos ficheiros, nas permissões e no arquivo.

9. Atualizar#

# 1. uma cópia de segurança primeiro, sempre — no ecrã Cópias de segurança

# 2. o código
cd /var/www/toutadmin
git pull
npm ci --omit=dev

# 3. reiniciar; a base atualiza-se sozinha no arranque
sudo systemctl restart toutadmin
journalctl -u toutadmin -n 30 --no-pager

O esquema evolui por migrações idempotentes: repetir a atualização não parte nada. data/ e .env nunca são tocados.

Voltar atrás#

Reponha o código na versão anterior e reinicie. As migrações não apagam colunas: uma base migrada continua legível pela versão anterior, salvo menção explícita no registo de versões. Na dúvida, reponha o arquivo tirado no passo 1.

10. Fazer cópias a sério#

O arquivo tar.gz leva a base e as cinco pastas de ficheiros. A base é copiada pela cópia em linha do SQLite, que produz uma cópia coerente mesmo durante uma escrita — a edição PHP obtém o mesmo resultado por VACUUM INTO. Cada ficheiro leva o seu resumo SHA-256, verificado na reposição.

Um arquivo que fica no servidor que protege não protege nada: configure um destino remoto (FTPS ou Google Drive) no ecrã Cópias de segurança, e subscreva um webhook a sauvegarde.echec para ser avisado quando a externalização falha. O pormenor está na página Cópias de segurança e reposição.

Experimentar primeiro localmente#

npm install
cp .env.example .env
npm run dev        # reinicia a cada alteração

Abra http://localhost:3000. Localmente, deixe NODE_ENV vazio: em production, os cookies são marcados «seguros» e não serão conservados numa ligação em claro — andaria às voltas na página de acesso.

Passar à edição PHP, ou vir dela#

As duas edições partilham o mesmo esquema — 142 tabelas, 1311 colunas — e o mesmo formato de palavra-passe. Pare uma, copie app.sqlite e as pastas de ficheiros, arranque a outra: não há conversão. Veja As duas edições.

Documentação do Toutadmin — construída em 2026-09-13. Site autónomo, independente do software.