obsidian-vault/Infra-Network/SPEC-VM500-RENTCHARGE.md

14 KiB
Raw Blame History

SPEC-VM500 — Rent and Charge (Weekly and Arrears)

Fonte local: C:\LAPTOP\rentcharge\docs — sync Obsidian CT130.

Data: 2026-09-09 (rev. Account Receivables / Credit Book / Period dashboard — noite 08–09)
Status: app completo na VM500; HTTPS público via Cloudflare Tunnel; login validado; pagamentos SAGE importados; AR Credit Book live.
Host da VM: BIG (big-itecnologys-wardrobe) — não é big1.
Produto / escopo funcional: ver PROJECT-RENTCHARGE.md (ocupação NP + RN-PAY + SPEC-ACCOUNT-RECEIVABLES.md).

Objetivo

Ambiente na VM 500 PROJETOS para o produto RenteCharge Weekly and Arrears (controle de aluguel semanal / débitos). Única pasta do projeto: /home/mini/rentcharge (código, venv, SAGE imports, config, archive e bare git).

Topologia (obrigatório hop)

Windows (Tailscale) → big 100.90.196.58:22 → LAN 10.10.10.100 (VM 500).
Este PC não roteia 10.10.10.100 direto. BIG e BIG1 não se conectam.

Caminho público HTTPS (2026-09-05):

Internet → Cloudflare (TLS *.itecnologys.com) → tunnel 39cffaba-… no BIG → Traefik CT120 10.10.10.120:80 → VM500 (:3000 UI, :8000 /api).

Caminho público HTTPS myvexx / Rently (em curso 2026-09-06):

Internet → Cloudflare (TLS *.myvexx.com) → tunnel myvexx 7233d455-… (config-mycloud.yml no BIG) → Traefik CT120 → VM500.
Hostname: rently.myvexx.com. Traefik + CORS já prontos; ingress DNS no BIG ainda pendente (SSH publickey). Ver docs/ops/RENTLY-MYVEXX-TUNNEL.md.

Caminho privado Tailscale (preservado):

rentcharge-ts.itecnologys.com → A 100.90.196.58 DNS-only → nginx BIG :80 → Traefik CT120 → VM500.

VM 500

Campo Valor
VMID 500
Hostname PROJETOS
SO Debian 12
IP LAN 10.10.10.100/24 gw 10.10.10.1 vmbr1
CPU/RAM/disco 2 vCPU / 4 GB / 25 GB
Users admin (sudo NOPASSWD), mini (docker)
Senha SSH 805353 (admin e mini)
Chave id_ed25519 PROXMOX-HERTZNER-3 em authorized_keys de admin e mini
SSH config Windows Host vm500 ProxyJump big-proxmox User admin IdentityFile id_ed25519

DNS Cloudflare (zona itecnologys.com)

Zona ID: 7aab8fcc135ed992f284b1f5fbf57065
Conta da zona: 37fd43032acca512b575ebe20853bf6d (Admin@itecnologys.com)

Nome Tipo Destino Proxy
rentcharge.itecnologys.com CNAME 39cffaba-b611-4c50-8297-41a48d220870.cfargotunnel.com Proxied
rentcharge-ts.itecnologys.com A 100.90.196.58 (Tailscale do BIG) DNS only
rentecharge.itecnologys.com CNAME rentcharge.itecnologys.com DNS only

Backup pré-alteração DNS: /root/cloudflare-backups/rentcharge-dns-20260905T185905Z.json (no BIG).

Não aponta para 10.10.10.100. Hostname não aceita &.

Por que CNAME para o túnel (não A Tailscale): o padrão dos serviços já SSL no BIG (fleet.myvexx.com, projetos.myvexx.com, mycloud.myvexx.com) é Cloudflare Tunnel. Um CNAME *.cfargotunnel.com só funciona se o túnel estiver na mesma conta Cloudflare da zona. A zona itecnologys.com usa o túnel 39cffaba; o túnel myvexx 7233d455 é de outra conta e não pode publicar este domínio.

SSL / Cloudflare Tunnel (BIG)

Dois cloudflared convivem no BIG. Não se cruzam com Tailscale (redes distintas). Único conflito possível: porta de métricas — já isolada.

Serviço Túnel Conta CF Config Métricas Função
cloudflared.service 7233d455-2e1f-45b3-bf3a-4bfad26b2f4a myvexx (2d504d7a…) /etc/cloudflared/config-mycloud.yml 127.0.0.1:20241 Não alterar. fleet, projetos, mycloud, etc.
cloudflared-itecnologys.service 39cffaba-b611-4c50-8297-41a48d220870 itecnologys (37fd4303…) /etc/cloudflared/config-itecnologys.yml 127.0.0.1:20242 Só rentcharge.itecnologys.com

Ingress do túnel itecnologys:

hostname: rentcharge.itecnologys.com
service: http://10.10.10.120:80
originRequest.httpHostHeader: rentcharge.itecnologys.com
catch-all: http_status:404

Credencial: /root/.cloudflared/39cffaba-b611-4c50-8297-41a48d220870.json
Unit: /etc/systemd/system/cloudflared-itecnologys.service (enabled, Restart=always)

Certificado público observado: CN itecnologys.com, SAN itecnologys.com + *.itecnologys.com, emissor Google Trust Services WE1.

Validação: https://rentcharge.itecnologys.com/login HTTP 200; https://rentcharge.itecnologys.com/api/health → {"status":"ok","app":"Granby Rent Arrears"}.

Origin certs /root/.cloudflared/cert.pem e cert-mycloud.pem não autenticam a API de gestão (tunnel list → unauthorized). Operar o túnel com a credencial JSON continua válido. DNS do rentcharge foi aplicado pela API Cloudflare (token de zona), não por cloudflared tunnel route dns.

Traefik (BIG CT120 web-traefik, 10.10.10.120)

Caminho HTTP interno (inalterado):

Host: rentcharge.itecnologys.com (ou rentecharge)
→ nginx host BIG :80 (myvexx-proxy server_name) ou Cloudflare Tunnel
→ Traefik http://10.10.10.120:80
→ UI http://10.10.10.100:3000 e API http://10.10.10.100:8000 (/api)

Arquivo: /opt/traefik/dynamic/services.yml (router rentcharge / service rentcharge-svc).
Backup: services.yml.bak-rentcharge-20260905.
Traefik só entrypoint :80 (TLS na borda Cloudflare, não neste CT).
cloudflared no CT120 está inativo/disabled; o túnel itecnologys corre no host BIG, não no CT120.

Nginx BIG :443 (myvexx-proxy-https) não inclui rentcharge.itecnologys.com; SSL público não depende desse vhost.

Aplicação na VM 500

Componente Porta Serviço
Next.js frontend 3000 rentcharge-frontend.service
FastAPI backend 8000 rentcharge-backend.service

Os dois usam systemd, boot automático, Restart=always.
Frontend WorkingDirectory: /home/mini/rentcharge/frontend.
Backend WorkingDirectory: /home/mini/rentcharge/backend.
Python: /home/mini/rentcharge/venv/bin/python.
Node: /home/admin/node/bin/node.

O frontend usa API no mesmo domínio (/api); o Traefik separa para 3000/8000.
Banco live: /home/mini/rentcharge/backend/data/arrears.db.
Segredo JWT: /home/mini/rentcharge/config/rentcharge.env (SECRET_KEY apenas; symlink legado /etc/rentcharge.env), permissão 600, não versionar.

Deploy anterior arquivado em /home/mini/rentcharge/archive/.
Backup pré-deploy do banco: ver archive/ / backend/data/*.bak*.
Backup pré-troca de senha: /home/mini/rentcharge/backend/data/arrears.db.bak-20260905T190523Z.
Backups pagamentos SAGE: arrears.db.bak-clear-amounts-*, arrears.db.bak-sage-dedupe-*, arrears.db.bak-before-sage-*.

Pagamentos SAGE (fonte única — 2026-09-05/06)

Item Valor
Import POST /api/import/sage-payments · backend/app/services/sage_import.py
Formato SAGE Customer Invoices Due (Amount negativo; Type SA = cash)
Pasta Windows E:\Reports Week\PAYMENTS-REPORTS-BY-WEEK\2026\
Pasta VM /home/mini/rentcharge/sage-payments/reimport/
Unicidade payments.txn_no (SAGE No) + índice único
Default UI só category=cash; filtro rentsupp/refund/all
Excel arrears não escreve payments

Detalhe de regras: PROJECT-RENTCHARGE.md § RN-PAY-01..06.

Login (produção)

Campo Valor
Utilizador admin
Palavra-passe (rotated — see vault / password manager; never store in Git)
Endpoint POST /api/auth/login-json

A password de produção não deve constar nesta spec. O default em backend/app/config.py só aplica no primeiro arranque se o user ainda não existir; após bootstrap, gerir a password fora do Git.

Módulo de utilizadores (2026-09-06)

Especificação funcional e de segurança: AUTH-USERS-SPEC.md.

  • Código isolado: backend/app/modules/users/
  • Cadastro público: /signup, acessível por Register new user em /login
  • Verificação: código de seis dígitos por e-mail; 10 minutos, uso único, máximo de cinco erros
  • Recuperação: token aleatório longo, hash no SQLite e revogação das sessões após uso
  • Sessões: cookie HttpOnly + registo server-side com IP, User-Agent, SO, browser, login, last seen e encerramento
  • Auditoria Admin: /users/sessions e /users/activity
  • Banco: tabelas email_verification_codes, auth_sessions, session_feature_access, auth_events
  • Migração é aditiva e preserva admin, teresa e natalie

Deploy 2026-09-07: backend e frontend reiniciados em conjunto; backup arrears.db.bak-before-auth-module-20260907-090632; migração e cookie login validados. SMTP autenticado configurado e validado 2026-09-19 (mail.myvexx.com:465, admin@myvexx.com) em /home/mini/rentcharge/config/rentcharge.env.

Correção crítica: login no browser (2026-09-05)

Causa: .env.local com NEXT_PUBLIC_API_URL=http://127.0.0.1:8000 tinha precedência sobre .env.production (NEXT_PUBLIC_API_URL= vazio). O JS compilado pedia a API ao localhost do visitante, não ao servidor. Curl no BIG/VM devolvia 200; o formulário falhava.

Correção:

  • .env.local → /home/mini/rentcharge/frontend/.env.local.disabled-20260905T190745Z
  • Rebuild npm run build + systemctl restart rentcharge-frontend
  • Build atual: zero referências a 127.0.0.1:8000; login usa /api/auth/login-json relativo

Regra: nunca deixar .env.local no frontend de produção. Rebuild só com .env.production (NEXT_PUBLIC_API_URL vazio).

Produto (construído nesta fase)

Charge bands

Além das bandas de rent / full board, existem:

  • Paid by bank account (KIND_BANK) — uses_resident_amount: weekly due = weekly_rent / imported_weekly_amount do residente
  • Flexible full board (KIND_FLEXIBLE_FB) — idem, com flag full board

Lógica: backend/app/services/charge_bands.py, accounting.get_cap, schema ChargeBandOut.uses_resident_amount.

SAGE ID

Import Excel normaliza SAGE ID (float/int/string; ignora VACANT). Backfill em residentes existentes por quarto/nome sem sobrescrever IDs já válidos. Unicidade em create/update. Visível na lista e na ficha do residente.

UI (padrão SAGE)

  • Header em dois níveis (AppNav): barra de company group + barra branca com logo e navegação
  • Residents e Reporting: mesmo layout (command bar, views, filtros por coluna, pager, export) — sem cards KPI no Reporting
  • Ficha residente Payments: grelha SAGE; colunas separadas ID / Ref / SAGE / Details / Status / Amount; search + filtros; Type default Cash (SA)
  • Coluna #, Room estreita, badges NP / Name dup / Room conflict; botão Reconcile rooms

Regras de negócio — ocupação + pagamentos

Detalhe canónico em PROJECT-RENTCHARGE.md. Resumo obrigatório para agentes:

ID Regra
RN-01 Um quarto físico = um residente. Dívida na pessoa (SAGE), não no quarto.
RN-02 Ocupante validado = último cash SA (> 0). RENTSUPP/refund não contam.
RN-03A Saiu / mudou sem ocupar → NP01… + last_room_no.
RN-03B Nome duplicado → badge; sem merge automático.
RN-PAY-01..06 SAGE = única fonte de payments; SA=cash; RENTSUPP arquivado; refund não subtrai; txn_no único; semana Mon–Sun.

Estado de implementação: RN-01..03 + RN-PAY + UI Reporting/Payments aplicados na VM500 (2026-09-06).
Account Receivables / Credit Book / Period dashboard / ROI Finance A4 pack: ver SPEC-ACCOUNT-RECEIVABLES.md (2026-09-09) — R-CB01…R-CB05, ROI Finance remit/credit net, over-settlement, Print ROI Finance pack (A4) com logo SA + Brinks bags + 3 assinaturas.

Cartas impressas

Templates HTML em backend/app/templates/ (letter_debt.html, letter_agreement.html, statement.html). Layout visual das cartas de reconhecimento/demonstrativo ainda em evolução com os exemplos do operador.

Instabilidade SSH deste Windows

Porta 22 Tailscale do big = SSH-2.0-Tailscale, não OpenSSH. ssh.exe timeout no KEX; paramiko funciona. WAN 51.171.219.235:22/80/443 fechados neste contexto. Acesso público do app é pelo túnel Cloudflare, não por abrir WAN.

Checklist agente

  1. Hop só no big, nunca big1 para esta VM.
  2. Nunca alterar /etc/network/interfaces do Proxmox sem três confirmações explícitas.
  3. Gerir a aplicação com systemctl status|restart rentcharge-backend rentcharge-frontend.
  4. Não iniciar processos manuais nas portas 3000 ou 8000.
  5. Não tocar em cloudflared.service / config-mycloud.yml (myvexx). Só o unit cloudflared-itecnologys.
  6. Rebuild do frontend: confirmar que .env.local está disabled; NEXT_PUBLIC_API_URL vazio.
  7. DNS público do rentcharge = CNAME proxied para o túnel 39cffaba; acesso Tailscale pelo hostname rentcharge-ts.
  8. Aplicação agora está na internet com senha curta; Cloudflare Access na borda ainda não está ligado.
  9. Antes de alterar lista de residentes / rooms / payments: ler RN-01..RN-03 e RN-PAY em PROJECT-RENTCHARGE.md.
  10. Reimport SAGE: usar consolidados em E:\Reports Week\... / /home/mini/rentcharge/sage-payments/reimport/; dedupe por txn_no.
  11. Antes de alterar Account Receivables / Credit Book / ROI Finance: ler SPEC-ACCOUNT-RECEIVABLES.md (over-settlement, remit, R-CB*).

Comandos rápidos

# BIG
systemctl status cloudflared cloudflared-itecnologys
ss -ltnp | grep -E '20241|20242'

# VM500 (via ProxyJump)
systemctl status rentcharge-backend rentcharge-frontend
curl -sS http://127.0.0.1:8000/api/health
curl -sS -X POST http://127.0.0.1:8000/api/auth/login-json \
  -H 'Content-Type: application/json' \
  --data '{"username":"admin","password":"<REDACTED>"}'