commit 3046d7d0dd1380eedd7846e3b0de784e2dfc4977
parent 8f21b46d62364b6f11a92b0d06efa97dd079ac74
Author: Pablo Murad <pablo@pablomurad.com>
Date: Fri, 27 Mar 2026 01:31:41 -0300
docs
Diffstat:
| D | DOCS_REBUILD_CHANGELOG.md | | | 111 | ------------------------------------------------------------------------------- |
| A | docs/admin.md | | | 536 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 536 insertions(+), 111 deletions(-)
diff --git a/DOCS_REBUILD_CHANGELOG.md b/DOCS_REBUILD_CHANGELOG.md
@@ -1,111 +0,0 @@
-# Changelog da reconstrução da documentação (runv-server)
-
-Documento em **pt-BR**. Data da passagem: conforme o commit em que este ficheiro foi adicionado.
-
-## Ficheiros criados (canónico `docs/`)
-
-| Ficheiro | Função |
-|----------|--------|
-| [docs/README.md](docs/README.md) | Porta de entrada, ordem de leitura, mapa rápido |
-| [docs/00-overview.md](docs/00-overview.md) | Visão geral, limites público/privado, fontes de verdade |
-| [docs/01-server-baseline-debian.md](docs/01-server-baseline-debian.md) | Debian, tempo, locale, pré-requisitos |
-| [docs/02-admin-access-and-ssh.md](docs/02-admin-access-and-ssh.md) | Modelo root/admin, SSH |
-| [docs/03-paths-files-and-state.md](docs/03-paths-files-and-state.md) | Caminhos `/var/lib/runv`, logs, email, web |
-| [docs/04-bootstrap-and-base-system.md](docs/04-bootstrap-and-base-system.md) | `starthere.py`, quotas ext4, Apache, UFW |
-| [docs/05-tools-and-system-experience.md](docs/05-tools-and-system-experience.md) | `tools.py`, MOTD, skel, jail SSH |
-| [docs/06-site-and-apache.md](docs/06-site-and-apache.md) | `genlanding.py`, DocumentRoot, TLS |
-| [docs/07-public-members-directory.md](docs/07-public-members-directory.md) | `build_directory.py`, `members.json`, privacidade |
-| [docs/08-email.md](docs/08-email.md) | Mailgun, legado msmtp, ficheiros de estado |
-| [docs/09-terminal-entre.md](docs/09-terminal-entre.md) | Conta `entre`, fila, limites (não provisiona Unix) |
-| [docs/10-user-provisioning-and-admin-ops.md](docs/10-user-provisioning-and-admin-ops.md) | `create_runv_user.py`, fluxo de aprovação |
-| [docs/11-daily-operations.md](docs/11-daily-operations.md) | Operação corrente |
-| [docs/12-security-and-privacy.md](docs/12-security-and-privacy.md) | Confiança, dados sensíveis |
-| [docs/13-troubleshooting.md](docs/13-troubleshooting.md) | Erros frequentes |
-| [docs/14-smoke-tests-and-validation.md](docs/14-smoke-tests-and-validation.md) | Verificações seguras |
-| [docs/15-glossary-and-reference.md](docs/15-glossary-and-reference.md) | Glossário, índice de scripts |
-| [docs/diagrams/architecture.mmd](docs/diagrams/architecture.mmd) | Sequência SSH entre → fila (Mermaid) |
-| [docs/diagrams/member-flow.mmd](docs/diagrams/member-flow.mmd) | Fluxo pedido → admin → dados públicos (Mermaid) |
-
-## Actualizações posteriores (código + docs)
-
-- **`genlanding.py --sync-public-only`:** cópia de `site/public/` para o DocumentRoot + `members.json`, sem reconfigurar Apache (`site/genlanding.py` v0.05).
-- **`create_runv_user.py`:** após criar membro, invoca esse modo em vez de só `build_directory.py`; `--no-refresh-landing-members` omite cópia e JSON.
-- **MOTD** [`tools/motd/60-runv`](tools/motd/60-runv): título “Últimos usuários online” sem o sufixo explicativo entre parêntesis.
-- Documentação actualizada: `docs/06`, `docs/07`, `docs/10`, `docs/11`, `docs/13`, `docs/15`.
-
----
-
-Alteração mínima **fora** de `docs/` para não quebrar referências em código ou templates (reconstrução inicial):
-
-- [README.md](README.md) (raiz): ponteiro para `docs/README.md`.
-- `tools/tools.py`, `site/build_directory.py`, `email/configure_mailgun.py`, `email/configure_msmtp_legacy.py`: docstrings / mensagens apontam para `docs/…` em vez de `.md` removidos nos módulos.
-- `terminal/templates/admin_mail.txt`: linha de ajuda ao admin aponta para `docs/10-user-provisioning-and-admin-ops.md` (antes referia `terminal/docs/ADMIN.md`, removido).
-
-**Nota:** existiu cópia errónea em `dev-notes/DOCS_REBUILD_CHANGELOG.md`; foi removida — a versão canónica é **sempre** este ficheiro na raiz.
-
-## Fontes de evidência usadas
-
-- Código Python em `scripts/admin/`, `terminal/`, `site/`, `tools/`, `email/`, `patches/`.
-- `terminal/config.example.toml`, exemplos em `site/example-users.json`.
-- Documentação modular **antes da remoção**: `INSTALL.md` (raiz), `site/*.md`, `terminal/docs/*.md`, `tools/docs/*.md`, `email/docs/*.md`, `scripts/**/*.md`, `dev-notes/RUNV_CURRENT_STATE_AUDIT.md`.
-- `terminal/docs/ARCHITECTURE.md` (fluxo e componentes).
-- Diff e defaults nos scripts (caminhos predefinidos, flags).
-
-## Contradições identificadas e como foram tratadas
-
-1. **Cron vs refresh “sem cron”**
- - `INSTALL.md` sugeria exemplo de cron para `build_directory.py`.
- - `site/README.md` enfatizava refresh via `create_runv_user.py` / `genlanding.py` sem cron.
- - **Resolução:** em `docs/07-public-members-directory.md` (e operações diárias) ficam explícitos **dois modos válidos**: regeneração automática nos fluxos de provisionamento/landing **ou** cron/manual — não são mutuamente exclusivos.
-
-2. **`USO.md` inexistente**
- - `terminal/docs/ARCHITECTURE.md` referia `USO.md`, que não existia no repositório.
- - **Resolução:** descrito em `docs/09-terminal-entre.md` e neste changelog; o fluxo cobre-se nos docs canónicos.
-
-3. **Múltiplos `INSTALL.md` por módulo**
- - Conteúdo sobreposto entre raiz e `tools/`, `email/`, `terminal/`.
- - **Resolução:** um único percurso numerado em `docs/01`–`docs/11`, com secções por componente.
-
-## O que ficou explicitamente **NÃO VERIFICADO** neste ambiente
-
-- Execução de `--help` e comportamento em runtime de `scripts/admin/create_runv_user.py`, `terminal/setup_entre.py` e `site/genlanding.py` em **Windows**: falham no import (`fcntl` / `grp` inexistentes). **Verificação plena:** correr em **Debian/Linux** alvo.
-- Estado real de um servidor de produção (Apache vhosts, TLS, quotas aplicadas, conteúdo de `/var/lib/runv/users.json`): apenas inferência a partir de defaults no código — qualquer deploy concreto deve ser confirmado no servidor.
-
-## Verificações executadas (2026-03-22, Windows / PowerShell)
-
-| Comando | Resultado |
-|---------|-----------|
-| `python -m compileall -q scripts terminal site tools email patches` | Exit 0 |
-| `cd email && python -m pytest tests/ -q` | 11 passed |
-| `python site/build_directory.py --users-json site/example-users.json --dry-run` | JSON válido no stdout (`username`, `since`, `path`) |
-| `python site/build_directory.py --help` | Exit 0 |
-| `python email/configure_mailgun.py --help` | Exit 0 |
-| `python scripts/admin/create_runv_user.py --help` | **Falha:** `ModuleNotFoundError: fcntl` |
-| `python terminal/setup_entre.py --help` | **Falha:** `ModuleNotFoundError: grp` |
-| `python site/genlanding.py --help` | **Falha:** `ModuleNotFoundError: grp` |
-| `git status -sb` | Registado no momento da passagem (working tree com `docs/` e alterações pendentes) |
-
-## Pressupostos dependentes do ambiente (operador)
-
-- **Um único host Debian** com paths tipo `/var/www/runv.club/html`, `/var/lib/runv/`, `/opt/runv/terminal/` — são defaults no código; outros caminhos exigem flags explícitas.
-- **Root/sudo** para bootstrap, `tools.py`, email, `entre`, provisionamento de utilizadores.
-- **Decisões de segurança** (firewall, TLS, política de passwords SSH) combinam o que o repo automatiza com o que o operador mantém — ver `docs/02` e `docs/12`.
-
-## Documentação `.md` removida nesta reconstrução
-
-Removidos de propósito para evitar duplicação e contradições com `docs/` (lista não exaustiva de paths relativos à raiz do repo):
-
-- `INSTALL.md`
-- `dev-notes/RUNV_MEMBER_BUBBLE_CHANGELOG.md` (changelog local; conteúdo operacional relevante está em `docs/07` e `docs/10`)
-- `dev-notes/RUNV_CURRENT_STATE_AUDIT.md`
-- `site/README.md`, `site/build_directory.md`, `site/genlanding.md`, `site/news/README.md`
-- `terminal/README.md`, `terminal/docs/INSTALL.md`, `terminal/docs/ARCHITECTURE.md`, `terminal/docs/ADMIN.md`
-- `tools/README.md`, `tools/skel/README.md`, `tools/docs/INSTALL.md`, `tools/docs/ADMIN.md`, `tools/docs/USER_EXPERIENCE.md`
-- `email/README.md`, `email/docs/INSTALL.md`, `email/docs/ADMIN.md`, `email/docs/INTEGRATION.md`, `email/docs/TROUBLESHOOTING.md`
-- `scripts/starthere.md`, `scripts/skel.md`, `scripts/create_runv_user.md`, `scripts/del-user.md`, `scripts/admin/perm1.md`, `scripts/doom/doom.md`, `scripts/docs/*.md`
-
-**Não removido:** `email/.pytest_cache/README.md` (artefacto gerado por pytest; não é documentação do produto).
-
-## Adequação para um operador novo
-
-A documentação é **utilizável** para alguém que não escreveu o código, desde que leia `docs/README.md` na ordem sugerida e execute verificações em **Debian** onde os scripts Unix são relevantes. Lacunas conhecidas estão marcadas como NÃO VERIFICADO ou recomendação, sem afirmar CI/deploy que não exista no repositório.
diff --git a/docs/admin.md b/docs/admin.md
@@ -0,0 +1,536 @@
+# Guia do Administrador
+
+Manual prático para operações administrativas do `runv-server` no servidor Debian do `runv.club`.
+
+Use este documento como folha de referência rápida. Quando houver dúvida sobre comportamento detalhado, a fonte de verdade continua sendo o código dos scripts em `scripts/`, `tools/`, `site/`, `terminal/`, `patches/` e a árvore `docs/`.
+
+## Convenções
+
+Assuma:
+
+```bash
+cd /caminho/para/runv-server
+```
+
+Nos exemplos abaixo, substitua:
+
+- `REPO` pelo caminho real do clone
+- `USER` pelo username Unix do membro
+- `EMAIL` pelo email do membro
+- `PUBKEY.pub` pelo arquivo `.pub` aprovado
+
+## Pré-requisitos
+
+- Executar como `root` ou com `sudo`
+- Servidor Debian com Python 3
+- Quotas ext4 prontas se for usar quota automática
+- Apache / DocumentRoot configurados se quiser refresh público automático
+
+## Bootstrap inicial do servidor
+
+Bootstrap conservador do host:
+
+```bash
+sudo python3 REPO/scripts/admin/starthere.py --verbose
+```
+
+Simular sem alterar:
+
+```bash
+sudo python3 REPO/scripts/admin/starthere.py --dry-run --verbose
+```
+
+## Ferramentas globais, MOTD, skel e IRC
+
+Aplicar ferramentas globais, `MOTD`, `skel`, drop-in SSH jailed e patch IRC:
+
+```bash
+sudo python3 REPO/tools/tools.py
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/tools/tools.py --dry-run --verbose
+```
+
+Reaplicar só arquivos e patch IRC, sem APT:
+
+```bash
+sudo python3 REPO/tools/tools.py --skip-apt
+```
+
+## Setup do onboarding via SSH (`entre`)
+
+Instalar/configurar o usuário `entre` e o fluxo de pedido:
+
+```bash
+sudo python3 REPO/terminal/setup_entre.py --help
+```
+
+Exemplo de execução:
+
+```bash
+sudo python3 REPO/terminal/setup_entre.py
+```
+
+## Fila de pedidos
+
+Fila padrão:
+
+- `/var/lib/runv/entre-queue/`
+
+Listar pedidos:
+
+```bash
+sudo ls -lah /var/lib/runv/entre-queue
+```
+
+Inspecionar um pedido JSON:
+
+```bash
+sudo cat /var/lib/runv/entre-queue/ID_DO_PEDIDO.json
+```
+
+Ou com formatação:
+
+```bash
+sudo jq . /var/lib/runv/entre-queue/ID_DO_PEDIDO.json
+```
+
+Log do onboarding:
+
+```bash
+sudo tail -n 200 /var/log/runv/entre.log
+```
+
+## Criar usuário novo
+
+Fluxo canônico de provisionamento:
+
+```bash
+sudo python3 REPO/scripts/admin/create_runv_user.py \
+ --username USER \
+ --email EMAIL \
+ --public-key-file PUBKEY.pub
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/scripts/admin/create_runv_user.py \
+ --username USER \
+ --email EMAIL \
+ --public-key-file PUBKEY.pub \
+ --dry-run --verbose
+```
+
+Exigir quota pronta antes de criar:
+
+```bash
+sudo python3 REPO/scripts/admin/create_runv_user.py \
+ --username USER \
+ --email EMAIL \
+ --public-key-file PUBKEY.pub \
+ --require-quota
+```
+
+Criar sem quota:
+
+```bash
+sudo python3 REPO/scripts/admin/create_runv_user.py \
+ --username USER \
+ --email EMAIL \
+ --public-key-file PUBKEY.pub \
+ --no-quota
+```
+
+Criar sem jail:
+
+```bash
+sudo python3 REPO/scripts/admin/create_runv_user.py \
+ --username USER \
+ --email EMAIL \
+ --public-key-file PUBKEY.pub \
+ --no-jail
+```
+
+Criar com valores de quota explícitos:
+
+```bash
+sudo python3 REPO/scripts/admin/create_runv_user.py \
+ --username USER \
+ --email EMAIL \
+ --public-key-file PUBKEY.pub \
+ --quota-soft-mb 450 \
+ --quota-hard-mb 500 \
+ --quota-inode-soft 10000 \
+ --quota-inode-hard 12000
+```
+
+Modo interativo:
+
+```bash
+sudo python3 REPO/scripts/admin/create_runv_user.py --interactive
+```
+
+## Atualizar usuário existente
+
+Abrir menu interativo:
+
+```bash
+sudo python3 REPO/scripts/admin/update_user.py --interactive --username USER
+```
+
+Atualizar email:
+
+```bash
+sudo python3 REPO/scripts/admin/update_user.py --username USER --email EMAIL
+```
+
+Substituir chave pública:
+
+```bash
+sudo python3 REPO/scripts/admin/update_user.py \
+ --username USER \
+ --ssh-replace-file PUBKEY.pub
+```
+
+Acrescentar chave pública:
+
+```bash
+sudo python3 REPO/scripts/admin/update_user.py \
+ --username USER \
+ --ssh-append-file PUBKEY.pub
+```
+
+Definir nova senha de login:
+
+```bash
+sudo python3 REPO/scripts/admin/update_user.py --username USER --set-password
+```
+
+Alterar quota:
+
+```bash
+sudo python3 REPO/scripts/admin/update_user.py \
+ --username USER \
+ --quota-soft-mb 450 \
+ --quota-hard-mb 500 \
+ --quota-inode-soft 10000 \
+ --quota-inode-hard 12000
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/scripts/admin/update_user.py \
+ --username USER \
+ --email EMAIL \
+ --dry-run
+```
+
+## Remover usuário / banimento técnico
+
+Remover conta e home:
+
+```bash
+sudo python3 REPO/scripts/admin/del-user.py --username USER
+```
+
+Execução não interativa:
+
+```bash
+sudo python3 REPO/scripts/admin/del-user.py --username USER -y
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/scripts/admin/del-user.py --username USER --dry-run
+```
+
+Observações:
+
+- o script desmonta jail/binds antes de remover
+- atualiza `users.json`
+- pode sincronizar a landing pública após a remoção
+
+## Remoção em massa
+
+Ferramenta perigosa, só com backup:
+
+```bash
+sudo python3 REPO/scripts/doom/doom.py --help
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/scripts/doom/doom.py --dry-run
+```
+
+## Reparar Gopher e Gemini
+
+Reconfigurar infraestrutura de Gopher e Gemini:
+
+```bash
+sudo python3 REPO/scripts/admin/setup_alt_protocols.py
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/scripts/admin/setup_alt_protocols.py --dry-run --verbose
+```
+
+Sem instalar pacotes:
+
+```bash
+sudo python3 REPO/scripts/admin/setup_alt_protocols.py --skip-install
+```
+
+Sem backfill de usuários:
+
+```bash
+sudo python3 REPO/scripts/admin/setup_alt_protocols.py --skip-backfill
+```
+
+## Site público e landing
+
+Primeira montagem completa da landing / Apache:
+
+```bash
+sudo python3 REPO/site/genlanding.py
+```
+
+Somente sincronizar `site/public` + `members.json` para o DocumentRoot:
+
+```bash
+sudo python3 REPO/site/genlanding.py --sync-public-only \
+ --document-root /var/www/runv.club/html \
+ --members-users-json /var/lib/runv/users.json
+```
+
+Atualizar só `members.json`:
+
+```bash
+sudo python3 REPO/site/build_directory.py \
+ --users-json /var/lib/runv/users.json \
+ -o /var/www/runv.club/html/data/members.json
+```
+
+## Notícias
+
+Publicar notícias novas:
+
+```bash
+sudo python3 REPO/site/news/publish_news.py
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/site/news/publish_news.py --dry-run
+```
+
+Publicar sem sincronizar Apache:
+
+```bash
+sudo python3 REPO/site/news/publish_news.py --skip-genlanding
+```
+
+## Wiki
+
+Gerar a wiki estática localmente a partir de `site/wiki/*.txt`:
+
+```bash
+python3 REPO/site/wiki/build_wiki.py
+```
+
+Depois, sincronizar a landing:
+
+```bash
+sudo python3 REPO/site/genlanding.py --sync-public-only \
+ --document-root /var/www/runv.club/html \
+ --members-users-json /var/lib/runv/users.json
+```
+
+## Email
+
+Configurar Mailgun:
+
+```bash
+sudo python3 REPO/email/configure_mailgun.py --help
+```
+
+Configurar msmtp:
+
+```bash
+sudo python3 REPO/email/configure_msmtp.py --help
+```
+
+Modo legado SMTP/msmtp:
+
+```bash
+sudo python3 REPO/email/configure_msmtp_legacy.py --help
+```
+
+Diagnóstico:
+
+```bash
+sudo sh REPO/email/scripts/diagnose_msmtp.sh
+```
+
+Teste de envio:
+
+```bash
+sudo sh REPO/email/scripts/send_test_mail.sh
+```
+
+## IRC da casa
+
+Aplicar/reaplicar a configuração IRC em todos os usuários:
+
+```bash
+sudo python3 REPO/patches/patch_irc.py --all-users
+```
+
+Aplicar a um único usuário:
+
+```bash
+sudo python3 REPO/patches/patch_irc.py --user USER
+```
+
+Simular:
+
+```bash
+sudo python3 REPO/patches/patch_irc.py --all-users --dry-run --verbose
+```
+
+Padrão atual:
+
+- servidor `irc.tilde.chat`
+- porta `6697`
+- TLS ligado
+- canal `#runv`
+- comando de uso do membro: `chat`
+
+## Moderação da comunidade e square
+
+### Política
+
+A política editorial e disciplinar está em:
+
+- [site/wiki/05_punicoes-e-moderacao.txt](/Z:/Códigos/runv-server/site/wiki/05_punicoes-e-moderacao.txt)
+- [site/wiki/04_regras-da-comunidade.txt](/Z:/Códigos/runv-server/site/wiki/04_regras-da-comunidade.txt)
+
+### O que este repositório faz
+
+Este repositório fornece os comandos para:
+
+- criar conta
+- atualizar conta
+- remover conta
+- regenerar presença pública
+- aplicar infraestrutura e serviços
+
+### O que este repositório não fornece
+
+Este snapshot **não inclui** um CLI canônico próprio para moderar a `square` em nível de posts, salas, threads, silenciamento, suspensão comunitária ou revisão de conteúdo dentro da aplicação social.
+
+Então, para `square`, a orientação operacional é:
+
+- aplicar a moderação pelos controles nativos da própria plataforma `square` que vocês já operam
+- registrar internamente a medida tomada
+- se a medida envolver perda de acesso ao servidor, complementar com `del-user.py` ou `update_user.py`, conforme o caso
+
+Exemplos de fluxo:
+
+1. Advertência ou limitação comunitária na `square`: usar a ferramenta da própria `square`; não há comando neste repo.
+2. Suspensão temporária na `square` sem remover conta Unix: executar na `square`; se necessário, ajustar quota, senha ou chaves com `update_user.py`.
+3. Banimento permanente com encerramento de conta no servidor: moderar na `square` e depois executar `del-user.py`.
+
+## Comandos de inspeção úteis
+
+Ver quotas:
+
+```bash
+quota -vs USER
+sudo repquota -s /home
+```
+
+Ver mounts:
+
+```bash
+mount | grep usrquota
+findmnt /home
+```
+
+Ver Apache:
+
+```bash
+sudo apache2ctl configtest
+sudo systemctl status apache2
+```
+
+Ver SSH:
+
+```bash
+sudo sshd -t
+sudo systemctl status ssh
+```
+
+Ver usuários com sessão:
+
+```bash
+who
+last
+```
+
+Ver logs do onboarding:
+
+```bash
+sudo tail -n 200 /var/log/runv/entre.log
+```
+
+## Fluxos rápidos
+
+### Aprovar pedido e criar conta
+
+```bash
+sudo jq . /var/lib/runv/entre-queue/ID_DO_PEDIDO.json
+sudo python3 REPO/scripts/admin/create_runv_user.py \
+ --username USER \
+ --email EMAIL \
+ --public-key-file PUBKEY.pub
+```
+
+### Corrigir perfil público
+
+```bash
+sudo python3 REPO/site/genlanding.py --sync-public-only \
+ --document-root /var/www/runv.club/html \
+ --members-users-json /var/lib/runv/users.json
+```
+
+### Corrigir IRC de todos os usuários
+
+```bash
+sudo python3 REPO/patches/patch_irc.py --all-users
+```
+
+### Banir tecnicamente uma conta
+
+```bash
+sudo python3 REPO/scripts/admin/del-user.py --username USER -y
+```
+
+## Referências rápidas
+
+- [docs/10-user-provisioning-and-admin-ops.md](/Z:/Códigos/runv-server/docs/10-user-provisioning-and-admin-ops.md)
+- [docs/11-daily-operations.md](/Z:/Códigos/runv-server/docs/11-daily-operations.md)
+- [docs/05-tools-and-system-experience.md](/Z:/Códigos/runv-server/docs/05-tools-and-system-experience.md)
+- [docs/06-site-and-apache.md](/Z:/Códigos/runv-server/docs/06-site-and-apache.md)
+- [docs/08-email.md](/Z:/Códigos/runv-server/docs/08-email.md)
+- [docs/09-terminal-entre.md](/Z:/Códigos/runv-server/docs/09-terminal-entre.md)