# Publicar o Metrixa na web

Guia para pôr o Metrixa num servidor próprio, com domínio e HTTPS. Serve para uma **VPS** (Hetzner, DigitalOcean, Contabo…) ou para um **servidor da h2n** com Ubuntu. No fim há um atalho para quem usar o **Laravel Forge** e as instruções para uma **hospedagem cPanel (Bluehost)**.

> **Antes de publicar:** o sistema guarda dados de beneficiários (nomes, telefones, GPS). Siga a [política de dados e partilha](politica-dados-e-partilha.md): servidor próprio, HTTPS, cópias de segurança diárias, e a escolha do alojamento (em Moçambique ou fora) aprovada pela direcção, tendo em conta a Lei de Protecção de Dados Pessoais e as regras dos doadores.

Nos exemplos, troque:

| Exemplo | Pelo seu valor |
|---|---|
| `metrixa.exemplo.org` | o domínio (ou subdomínio) do sistema |
| `deploy` | o utilizador Linux que corre o sistema |
| `/var/www/metrixa` | a pasta do sistema no servidor |
| `git@github.com:h2n/metrixa.git` | o repositório Git privado |

## 1. O que é preciso

- **Servidor:** Ubuntu 24.04, 2 GB de RAM e 2 CPU chegam para começar (fichas maiores ou muitas pessoas em simultâneo: 4 GB).
- **Domínio:** um registo DNS `A` de `metrixa.exemplo.org` para o IP do servidor.
- **Repositório Git privado** (GitHub ou GitLab) com o código.
- **Email (SMTP)** para os convites de utilizadores, a recuperação de palavra-passe e os resumos por email.
- **Acesso à internet a partir do servidor**, para ler as exportações do KoboToolbox.
- Opcional: uma chave da API da Anthropic para «Perguntar aos dados».

O alojamento partilhado comum **não serve**: o sistema precisa de PHP 8.4, PostgreSQL e de processos sempre ligados (a fila e o agendador).

## 2. Preparar o servidor

Entre como administrador (`ssh root@IP`) e instale os programas:

```bash
apt update && apt upgrade -y
apt install -y software-properties-common curl git unzip nginx postgresql supervisor
add-apt-repository -y ppa:ondrej/php && apt update
apt install -y php8.4-fpm php8.4-cli php8.4-pgsql php8.4-mbstring php8.4-xml php8.4-zip php8.4-gd php8.4-intl php8.4-bcmath php8.4-curl
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && apt install -y nodejs
```

Crie o utilizador que corre o sistema e abra só o necessário na firewall:

```bash
adduser --disabled-password --gecos "" deploy && usermod -aG www-data deploy
ufw allow OpenSSH && ufw allow 'Nginx Full' && ufw --force enable
```

## 3. Base de dados

```bash
sudo -u postgres psql -c "CREATE USER metrixa WITH PASSWORD 'TROQUE-POR-UMA-PALAVRA-PASSE-FORTE';"
sudo -u postgres psql -c "CREATE DATABASE metrixa OWNER metrixa;"
```

A base de dados só aceita ligações do próprio servidor (o PostgreSQL vem assim por omissão); não abra a porta 5432 na firewall.

## 4. Código

Como `deploy` (`su - deploy`), com uma chave SSH de leitura no repositório (*deploy key*):

```bash
sudo mkdir -p /var/www/metrixa && sudo chown deploy:www-data /var/www/metrixa
git clone git@github.com:h2n/metrixa.git /var/www/metrixa
cd /var/www/metrixa
composer install --no-dev --optimize-autoloader
npm ci && npm run build
cp .env.example .env
php artisan key:generate
```

## 5. Configuração (`.env`)

Edite `/var/www/metrixa/.env`. Valores de produção (o resto pode ficar como em `.env.example`):

```dotenv
APP_NAME="Metrixa"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://metrixa.exemplo.org
APP_LOCALE=pt

LOG_LEVEL=warning

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=metrixa
DB_USERNAME=metrixa
DB_PASSWORD=TROQUE-POR-UMA-PALAVRA-PASSE-FORTE

# Sessões no domínio do sistema, só por HTTPS.
SESSION_DRIVER=database
SESSION_DOMAIN=metrixa.exemplo.org
SESSION_SECURE_COOKIE=true
SANCTUM_STATEFUL_DOMAINS=metrixa.exemplo.org

QUEUE_CONNECTION=database
CACHE_STORE=database

# Email real (convites, recuperar palavra-passe, resumos semanais e mensais).
MAIL_MAILER=smtp
MAIL_HOST=smtp.exemplo.org
MAIL_PORT=587
MAIL_USERNAME=metrixa@exemplo.org
MAIL_PASSWORD=TROQUE
MAIL_FROM_ADDRESS="metrixa@exemplo.org"
MAIL_FROM_NAME="Metrixa"

# Opcional: «Perguntar aos dados».
ANTHROPIC_API_KEY=
```

Nunca ponha o `.env` no Git: tem as palavras-passe e a `APP_KEY` (que cifra as sessões).

Crie as tabelas e o primeiro administrador. **Não use `--seed`** em produção: cria as contas de demonstração `@example.test`.

```bash
php artisan migrate --force
php artisan datahub:create-admin email@h2n.org.mz "Nome Apelido" --organization="h2n" --platform
php artisan optimize
```

O administrador recebe um convite por email para escolher a palavra-passe. `--platform` faz dele também **administrador da plataforma** (vê todas as organizações). As outras organizações registam-se sozinhas em `https://metrixa.exemplo.org/criar-conta` e confirmam o email — por isso o email (SMTP) tem de estar a funcionar.

Permissões das pastas que o sistema escreve:

```bash
sudo chown -R deploy:www-data storage bootstrap/cache
sudo chmod -R ug+rwX storage bootstrap/cache
```

## 6. Nginx e HTTPS

Crie `/etc/nginx/sites-available/metrixa`:

```nginx
server {
    listen 80;
    server_name metrixa.exemplo.org;
    root /var/www/metrixa/public;
    index index.php;

    # Imagens e logótipos do painel vão na disposição (até ~1,5 MB cada).
    client_max_body_size 20m;

    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
        fastcgi_read_timeout 120;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}
```

Active o site e peça o certificado HTTPS gratuito (Let's Encrypt):

```bash
ln -s /etc/nginx/sites-available/metrixa /etc/nginx/sites-enabled/ && rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
apt install -y certbot python3-certbot-nginx
certbot --nginx -d metrixa.exemplo.org --redirect
```

O certificado renova-se sozinho.

## 7. Fila e agendador

A **fila** actualiza as fichas a partir do Kobo e envia os emails; o **agendador** faz as actualizações automáticas (de 5 em 5 minutos, conforme cada ficha) e os resumos das 07:00 (hora UTC).

Agendador, no cron de `deploy` (`crontab -e`):

```cron
* * * * * cd /var/www/metrixa && php artisan schedule:run >> /dev/null 2>&1
```

Fila sempre ligada, com o Supervisor. Crie `/etc/supervisor/conf.d/metrixa-worker.conf`:

```ini
[program:metrixa-worker]
command=php /var/www/metrixa/artisan queue:work --sleep=3 --tries=3 --max-time=3600
user=deploy
numprocs=1
autostart=true
autorestart=true
stopwaitsecs=300
redirect_stderr=true
stdout_logfile=/var/www/metrixa/storage/logs/worker.log
```

```bash
supervisorctl reread && supervisorctl update && supervisorctl status
```

## 8. Cópias de segurança

Cópia diária da base de dados (guardada 14 dias), no cron de `root`:

```cron
30 2 * * * mkdir -p /var/backups/metrixa && sudo -u postgres pg_dump -Fc metrixa > /var/backups/metrixa/metrixa-$(date +\%F).dump && find /var/backups/metrixa -name '*.dump' -mtime +14 -delete
```

Copie também essas cópias para **fora do servidor** (o fornecedor da VPS costuma ter *backups*/*snapshots*; ou um armazenamento externo), e guarde o `.env` num local seguro. Para repor: `pg_restore --clean -d metrixa ficheiro.dump`.

Teste a reposição uma vez, antes de precisar dela.

## 9. Publicar uma versão nova

Depois de enviar o código para o Git (`git push`), no servidor, como `deploy`:

```bash
cd /var/www/metrixa
php artisan down --retry=15
git pull --ff-only
composer install --no-dev --optimize-autoloader
npm ci && npm run build
php artisan migrate --force
php artisan optimize
php artisan queue:restart
php artisan up
```

Pode guardar estes passos num ficheiro `publicar.sh` no servidor. Antes de publicar, no computador de desenvolvimento, passe as verificações: `composer test`, `composer lint`, `npm test`, `npm run lint`, `npm run typecheck`.

## 10. Verificar que está tudo bem

- Abra `https://metrixa.exemplo.org` e entre com o administrador.
- **Fichas → Ligar ficha** com um link do Kobo: a ficha deve importar (prova que o servidor chega ao Kobo e que a fila corre).
- `supervisorctl status`: `metrixa-worker` em `RUNNING`.
- `php artisan schedule:list`: as tarefas agendadas aparecem.
- Crie um link público e abra-o numa janela privada (sem sessão).
- Peça a recuperação de palavra-passe para confirmar que o email sai.
- Erros: `storage/logs/laravel.log` e `storage/logs/worker.log`.

## Atalho: Laravel Forge

O [Laravel Forge](https://forge.laravel.com) (pago, por mês) faz os passos 2, 3, 6, 7 e 9 por si numa VPS sua:

1. Ligue o Forge ao fornecedor da VPS e ao GitHub/GitLab; crie um servidor do tipo **App server** com **PHP 8.4** e **PostgreSQL**.
2. Crie o site `metrixa.exemplo.org` com o repositório e a pasta `public`; active o **Let's Encrypt**.
3. Em **Environment**, cole o `.env` do passo 5.
4. Em **Deploy script**, acrescente `npm ci && npm run build` e `php artisan optimize`; active o **Quick deploy** (publica a cada `git push`).
5. Em **Queue**, crie um *worker* (`database`, 3 tentativas); em **Scheduler**, active o `schedule:run`.
6. Corra uma vez, em **Commands**: `php artisan migrate --force` e `php artisan datahub:create-admin email@h2n.org.mz "Nome" --organization="h2n" --platform`.
7. Configure as cópias de segurança da base de dados (**Database backups**) para um armazenamento externo.

## Hospedagem cPanel (Bluehost)

Também é possível usar uma hospedagem partilhada com cPanel, como a da **Bluehost**, **se o plano tiver PostgreSQL e PHP 8.4**. Serve para um piloto pequeno; para uso real com dados de beneficiários, a [política de dados](politica-dados-e-partilha.md) pede um servidor próprio (VPS ou servidor da h2n, como nas secções acima). Num **VPS da Bluehost**, siga as secções 1 a 10.

### A. Confirmar o plano (antes de tudo)

| No cPanel | Tem de haver | Se não houver |
|---|---|---|
| *Databases* | **PostgreSQL Databases** | Não serve: o sistema não funciona com MySQL/MariaDB (usa `jsonb` e funções do PostgreSQL). Peça ao suporte para activar ou mude para VPS. |
| *Software → MultiPHP Manager* | **PHP 8.4** na lista | Não serve (o projecto exige PHP 8.4). Peça ao suporte ou mude para VPS. |
| Portal Bluehost: *Websites → Manage → Files & Access → SSH* | **Shell Access** ligado | Active-o (o utilizador e a palavra-passe são os do cPanel; porta 22). |

Com o SSH ligado, confirme no terminal (`ssh UTILIZADOR@metrixa.exemplo.org`):

```bash
ls /opt/cpanel/ | grep ea-php
psql --version
curl -sI https://kf.kobotoolbox.org | head -1
```

- `ea-php84` tem de aparecer (é o PHP 8.4). Nos comandos abaixo usa-se o caminho completo `/opt/cpanel/ea-php84/root/usr/bin/php`, porque o `php` do terminal pode ser de outra versão.
- O `curl` tem de responder (`HTTP/…`): prova que o servidor chega ao Kobo. Se o seu Kobo for outro (ex.: `eu.kobotoolbox.org` ou da organização), teste esse endereço.

Para simplificar, crie um atalho para esta sessão:

```bash
alias php84=/opt/cpanel/ea-php84/root/usr/bin/php
```

### B. Base de dados

Em *cPanel → PostgreSQL Databases*:

1. **Create New Database:** `metrixa`. O cPanel acrescenta o prefixo da conta, ficando, por exemplo, `conta_metrixa`.
2. **Add New User:** `metrixa`, com uma palavra-passe forte. Fica, por exemplo, `conta_metrixa`.
3. **Add User To Database:** junte o utilizador à base de dados, com **todos os privilégios**.

Anote os nomes completos (com o prefixo): vão para o `.env`.

### C. Domínio e HTTPS

1. Em *cPanel → Domains*, crie o subdomínio (ex.: `metrixa.exemplo.org`) e mude a **Document Root** para `metrixa/public` (dentro da pasta da conta, **não** dentro de `public_html`).
2. Em *cPanel → SSL/TLS Status*, corra o **AutoSSL** para o subdomínio (certificado HTTPS gratuito).
3. Em *MultiPHP Manager*, escolha **PHP 8.4** para esse subdomínio.
4. Em *MultiPHP INI Editor*, para o subdomínio: `memory_limit = 512M`, `max_execution_time = 120`, `upload_max_filesize = 20M`, `post_max_size = 20M`.

O código fica **fora** de `public_html`: só a pasta `public` é visível na web. Assim o `.env` (com as palavras-passe) nunca fica exposto. O ficheiro `public/.htaccess` do projecto já encaminha os pedidos para o Laravel no Apache do cPanel.

### D. Código

No **seu computador**, gere os ficheiros do ecrã (a hospedagem normalmente não tem Node):

```bash
npm ci && npm run build
```

No **servidor** (SSH), na pasta da conta:

```bash
cd ~
git clone git@github.com:h2n/metrixa.git metrixa
```

Sem `git` no servidor (ou sem chave de acesso ao repositório), envie o projecto num `.zip` pelo *File Manager* do cPanel para `~/metrixa` e descompacte-o, **sem** as pastas `node_modules`, `vendor` e `.git`.

Envie a pasta **`public/build`** do seu computador para `~/metrixa/public/build` (pelo *File Manager* ou por `scp`):

```bash
scp -r public/build UTILIZADOR@metrixa.exemplo.org:~/metrixa/public/
```

Nunca envie o ficheiro `public/hot` (só existe com `npm run dev` e faria o ecrã procurar o servidor de desenvolvimento).

Instale as dependências do PHP:

```bash
cd ~/metrixa
curl -sS https://getcomposer.org/installer | php84 -- --filename=composer.phar
php84 composer.phar install --no-dev --optimize-autoloader
cp .env.example .env
php84 artisan key:generate
```

### E. Configuração (`.env`)

Use os valores da secção 5, com estas diferenças:

```dotenv
APP_URL=https://metrixa.exemplo.org

DB_HOST=localhost
DB_DATABASE=conta_metrixa
DB_USERNAME=conta_metrixa
DB_PASSWORD=A-PALAVRA-PASSE-DO-PASSO-B

SESSION_DOMAIN=metrixa.exemplo.org
SANCTUM_STATEFUL_DOMAINS=metrixa.exemplo.org

# Email: crie uma conta em cPanel → Email Accounts (ex.: metrixa@exemplo.org).
MAIL_MAILER=smtp
MAIL_HOST=mail.exemplo.org
MAIL_PORT=465
MAIL_SCHEME=smtps
MAIL_USERNAME=metrixa@exemplo.org
MAIL_PASSWORD=A-PALAVRA-PASSE-DA-CONTA-DE-EMAIL
MAIL_FROM_ADDRESS="metrixa@exemplo.org"
```

Os dados exactos do servidor de email aparecem em *Email Accounts → Connect Devices*.

Depois, crie as tabelas e o primeiro administrador (**sem** `--seed`):

```bash
php84 artisan migrate --force
php84 artisan datahub:create-admin email@h2n.org.mz "Nome Apelido" --organization="h2n" --platform
php84 artisan optimize
chmod -R u+rwX storage bootstrap/cache
```

### F. Fila e agendador (um só cron)

Na hospedagem partilhada não há Supervisor, mas não faz falta: o agendador do sistema já corre a fila a cada minuto (cada execução termina sozinha em até 4 minutos). Em *cPanel → Cron Jobs*, acrescente **uma** tarefa, *Once Per Minute* (`* * * * *`):

```bash
cd $HOME/metrixa && /opt/cpanel/ea-php84/root/usr/bin/php artisan schedule:run >> /dev/null 2>&1
```

Isto trata da actualização automática das fichas, das importações, dos convites, dos resumos por email e dos avisos de metas. Confirme com `php84 artisan schedule:list`.

### G. Cópias de segurança

- Em *cPanel → Backup*, descarregue regularmente a cópia da base de dados PostgreSQL e da pasta `metrixa` (com o `.env`), e guarde-as fora da Bluehost.
- Ou automatize uma cópia diária da base de dados com outro *Cron Job* (às 02:30), guardando 14 dias:

```bash
mkdir -p $HOME/backups && PGPASSWORD='A-PALAVRA-PASSE-DO-PASSO-B' pg_dump -h localhost -U conta_metrixa -Fc conta_metrixa > $HOME/backups/metrixa-$(date +\%F).dump && find $HOME/backups -name '*.dump' -mtime +14 -delete
```

As cópias dentro da mesma conta não protegem contra a perda da conta: descarregue-as também para outro sítio.

### H. Publicar uma versão nova

No seu computador: passe as verificações (`composer test`, `composer lint`, `npm test`, `npm run lint`, `npm run typecheck`), faça `npm run build`, `git push` e envie de novo a pasta `public/build` (passo D). No servidor:

```bash
cd ~/metrixa
php84 artisan down --retry=15
git pull --ff-only
php84 composer.phar install --no-dev --optimize-autoloader
php84 artisan migrate --force
php84 artisan optimize
php84 artisan queue:restart
php84 artisan up
```

### I. Limites da hospedagem partilhada

- **Memória e tempo limitados:** fichas muito grandes do Kobo (dezenas de milhares de linhas, Excel pesados) podem falhar a importar; nesse caso, VPS.
- **Velocidade:** com várias pessoas ao mesmo tempo, o painel fica mais lento do que numa VPS.
- **Servidor partilhado com outros clientes da Bluehost:** veja a política de dados antes de pôr lá dados de beneficiários.
- **Erros:** `~/metrixa/storage/logs/laravel.log` (e *cPanel → Errors* para os erros do Apache).
