# Spec funcional — VM112 Ligbox Onboard

**Data:** 2026-06-04  
**Host:** `mail.dratcoin.com` · `10.10.10.112`  
**Produto:** **Ligbox Onboard** (linha **Ligbox Mail**)  
**Repo:** `ibytera-mail-portal` · produção `/opt/ibytera-mail-portal`  
**Família:** [FAMILIA_PRODUTOS_LIGBOX_MAIL.md](../product/FAMILIA_PRODUTOS_LIGBOX_MAIL.md)

---

## 1. Identidade da VM

| Campo | Valor |
|-------|--------|
| **VMID Proxmox** | 112 |
| **Hostname** | `mail.dratcoin.com` |
| **IP LAN** | `10.10.10.112/24` |
| **IP público mail** | `95.216.14.146` (via CT114 / pfSense) |
| **SSH WAN (pfSense NAT)** | `95.216.14.146:2512` → VM112:22 |
| **SO** | Ubuntu 22.04/24.04, kernel 6.8.x |
| **RAM** | 11 GiB |
| **Disco** | `/dev/sda1` ~96 GB (~20 GB usados) |
| **Papel** | EmailServer Carbonio + **Ligbox Onboard** (único nó mail com wizard hoje) |

---

## 2. Família de produtos nesta VM

```
Ligbox Mail
└── Ligbox Onboard (VM112)     ← este documento
    ├── Landing Ligbox (/)
    ├── Wizard (/onboard)
    ├── Painel domínio (/admin) — parcial
    └── Motor Carbonio (8 domínios)
```

| Produto / módulo | Estado | Rota / interface |
|------------------|--------|------------------|
| **Ligbox Onboard** — wizard | ✅ Produção | `/onboard` |
| **Ligbox** — landing marketing | ✅ | `/` |
| **Domain Admin** — painel corporativo | 🔄 Parcial | `/admin` |
| **Carbonio EmailServer** | ✅ | `mail.*` :443, SMTP, IMAP |
| **Agente suporte IA** | ✅ Fases 1–3.1 | Modal no wizard + tickets |
| **Ligbox Ops Platform** | 📋 VM113 | Integração futura API/webhooks |

**UI marca (PRD-6 ✅):** cabeçalho wizard = **Ligbox Onboard** + `powered by Ibytera`.

---

## 3. Topologia — VMs e CTs ligados

```mermaid
flowchart TB
  subgraph Internet
    CF[Cloudflare API]
    Users[Clientes / Browser]
  end

  subgraph WAN["95.216.14.146"]
    CT114[CT114 Traefik + HAProxy SNI<br/>10.10.10.114]
  end

  subgraph LAN["10.10.10.0/24"]
    VM112[VM112 Ligbox Onboard + Carbonio<br/>10.10.10.112:8090 / :443]
    VM115[VM115 ntfy<br/>10.10.10.115:8091]
    VM113[VM113 Ligbox Ops — planeado<br/>10.10.10.113]
    PVE[Proxmox 95.216.14.162<br/>sync / workspace]
  end

  Users -->|HTTPS onboard.ibytera.com| CT114
  Users -->|HTTPS mail.dominio.com| CT114
  CT114 -->|HTTP :8090| VM112
  CT114 -->|HTTPS :443| VM112
  VM112 -->|SSH| CT114
  VM112 -->|zmprov local| VM112
  VM112 -->|HTTP notify| VM115
  VM112 -.->|API CF| CF
  VM112 -.->|webhooks futuro| VM113
  VM113 -.->|read API| VM112
  PVE -->|rsync deploy| VM112
```

### 3.1 Tabela de nós externos

| Nó | ID | IP | Portas | Ligação desde VM112 | Função |
|----|-----|-----|--------|---------------------|--------|
| **Proxmox** | host | `95.216.14.162` | SSH `4422` | rsync **para** VM112 (origem workspace) | Deploy, backup projeto |
| **CT114** | 114 | `10.10.10.114` | 443, 80, HAProxy | **SSH** `root@10.10.10.114` — edita Traefik/SNI | Terminação TLS WAN, roteamento |
| **VM115** | 115 | `10.10.10.115` | `8091` | **HTTP** `ntfy_internal_url` | Push notificações (`ntfy.ligbox.com.br`) |
| **VM113** | 113 | `10.10.10.113` (planeado) | TBD | **Futuro:** webhooks + API read | Ligbox Ops Platform |
| **pfSense** | VM? | `10.10.10.1` LAN | API `10443` | Indirecto (NAT) | Firewall / WAN |
| **Cloudflare** | SaaS | API | HTTPS | Token em `secrets/cloudflare.token` | Zonas DNS conta Ibytera |
| **LLM** | SaaS | — | HTTPS | `secrets/llm.env`, `kimi.env` | Gemini (primário), Kimi, OpenAI, Anthropic |

**Nota:** Acesso SSH à VM112 pela rede: `ssh -p 2512 root@95.216.14.146` (via pfSense WAN (95.216.14.146)).

---

## 4. Serviços em execução (systemd)

### 4.1 Ligbox Onboard

| Unidade | Estado | Descrição |
|---------|--------|-----------|
| `ibytera-mail-portal.service` | **active** | FastAPI + SPA estática, porta **8090** |

```ini
ExecStart=.../uvicorn app.main:app --host 0.0.0.0 --port 8090
WorkingDirectory=/opt/ibytera-mail-portal
After=carbonio-appserver.service
```

Health: `GET http://127.0.0.1:8090/api/onboarding/health` → `{"status":"ok"}`

### 4.2 Carbonio (EmailServer)

**~40 unidades** `carbonio-*` + sidecars. Principais:

| Serviço | Função |
|---------|--------|
| `carbonio-appserver` | Core mail (Java) |
| `carbonio-nginx` | Proxy webmail HTTPS :443 |
| `carbonio-postfix` | SMTP :25, :587 |
| `carbonio-openldap` | Diretório |
| `carbonio-milter` / `carbonio-antivirus` | Segurança mail |
| `carbonio-memcached` | Cache |

**zmprov:** `/opt/zextras/bin/zmprov` (utilizador `zextras`)

### 4.3 Portas em escuta (resumo)

| Porta | Processo | Uso |
|-------|----------|-----|
| **8090** | uvicorn | Ligbox Onboard API + SPA |
| **443** | carbonio-nginx | Webmail / admin Carbonio |
| **25, 587** | postfix | SMTP |
| **993** | nginx | IMAPS |
| **7071** | java | Admin SOAP (local/LAN) |
| **8080** | java | Appserver interno |

---

## 5. Domínios Carbonio (produção mail)

| Domínio | Webmail (público) | Portal registry |
|---------|-------------------|-----------------|
| `betinplace.com` | `mail.betinplace.com` | — |
| `betinsport.com` | `mail.betinsport.com` | — |
| `diarissima.com` | `mail.diarissima.com` | ✅ `diarissima.com.json` |
| `dratcoin.com` | `mail.dratcoin.com` | ✅ `dratcoin.com.json` |
| `eplacebets.com` | `mail.eplacebets.com` | — |
| `ibytera.com` | `mail.ibytera.com` | — |
| `iofficebooks.com` | `mail.iofficebooks.com` | — |
| `myvexx.com` | `mail.myvexx.com` | — |

**SNI CT114** (`sni_vm112.lst`): todos os `mail.*` acima.  
**Cert LE VM112:** `mail-vm112-multi` + legado `mail.ligbox.com.br`  
**zimbraPublicServiceHostname (global):** `mail.ligbox.com.br` — hostname por domínio via `zmprov` no onboard.

---

## 6. URLs públicas

| URL | Destino | TLS |
|-----|---------|-----|
| https://onboard.ibytera.com/onboard | CT114 → VM112:8090 | LE (CT114) |
| https://onboard.ibytera.com/ | Landing + rotas SPA | idem |
| https://onboard.ibytera.com/api/docs | OpenAPI | idem |
| https://mail.{dominio}/ | CT114 → VM112:443 | LE multi-SAN |
| http://10.10.10.112:8090 | LAN directo (debug) | — |
| https://ntfy.ligbox.com.br | VM115 (push público) | — |

**DNS:** registos `A` mail/onboard → `95.216.14.146` (sem proxy CF no mail).

---

## 7. Estrutura de diretórios

### 7.1 Código e deploy (`/opt/ibytera-mail-portal`)

```
/opt/ibytera-mail-portal/
├── backend/app/
│   ├── main.py              # FastAPI, monta SPA
│   ├── config.py            # Settings + secrets
│   ├── routers/
│   │   ├── onboarding.py    # Wizard API
│   │   ├── domain_admin.py  # /admin API
│   │   ├── corporate.py
│   │   └── portal_auth.py
│   └── services/
│       ├── carbonio.py      # zmprov, vhost nginx
│       ├── infrastructure.py # SSH CT114, certbot
│       ├── cloudflare.py
│       ├── support_agent.py / support_tickets.py
│       ├── domain_registry.py
│       └── ...
├── frontend/
│   ├── src/App.jsx          # Ligbox Onboard wizard
│   ├── src/ligbox/          # Landing /
│   └── dist/                # Build servido pelo uvicorn
├── secrets/                 # NÃO rsync (tokens)
│   ├── cloudflare.token
│   ├── llm.env
│   └── kimi.env
├── scripts/sync-all.sh      # Proxmox → 112 → Obsidian → LAPTOP
├── docs/
│   ├── architecture/        # Este spec
│   └── product/             # Família Ligbox Mail
├── .env                     # Config não-secreta
└── .venv/                   # Python 3.12
```

### 7.2 Dados runtime (`/var/lib/ibytera-mail-portal`)

| Pasta | Conteúdo |
|-------|----------|
| `domains/` | JSON por domínio onboarded (`*.json`) |
| `portal_users/` | Utilizadores portal / sessões |
| `tickets/` | Tickets suporte IA |
| `company_profiles/` | Perfil empresa wizard |

### 7.3 Carbonio

| Pasta | Uso |
|-------|-----|
| `/opt/zextras/` | Binários Carbonio |
| `/opt/zextras/conf/nginx/` | **carbonio-nginx** vhosts |
| `/opt/zextras/log/` | Logs mail (futuro SOC) |
| `/etc/letsencrypt/live/mail-vm112-multi/` | Cert multi-domínio |

### 7.4 CT114 (remoto via SSH)

| Ficheiro | Uso |
|----------|-----|
| `/root/traefik/dynamic.yml` | Routers Traefik (onboard + mail.*) |
| `/root/traefik/haproxy-mail-sni/maps/sni_vm112.lst` | Mapa SNI → backend 112 |
| Docker: `traefik`, `mail-sni-proxy` | Edge HTTPS |

---

## 8. API Ligbox Onboard (resumo)

**Prefixo:** `/api/onboarding` · sessão: header `X-Onboarding-Session`

| Grupo | Endpoints principais |
|-------|---------------------|
| Sessão | `POST /session/reset` |
| Domínio | `POST /validate-domain` |
| DNS CF | `POST /dns/cloudflare/provision-zone`, `POST /dns/cloudflare/apply`, `GET /dns/verify/{domain}` |
| Conta | `POST /account/create` |
| Infra | `GET /infrastructure/status/{domain}`, `POST /infrastructure/provision` |
| Suporte | `POST /support/ticket`, `POST .../message`, `POST .../escalate` |
| Perfil | `GET/PUT /company-profile`, `POST .../finalize` |
| Log | `GET /activity-log` |

**Domain admin:** `/api/domain-admin/*` (login, contas, quota, 2FA).

---

## 9. Pipeline infra (wizard → CT114 + VM112)

Ordem em `infrastructure.provision`:

1. **haproxy_sni** — adiciona `mail.{dom}` em `sni_vm112.lst` (CT114)  
2. **traefik_router** — router `mail-*-Router` em `dynamic.yml` (CT114)  
3. **certbot** — SAN em `mail-vm112-multi` (VM112)  
4. **carbonio_hostname** — `zimbraPublicServiceHostname` por domínio  
5. **carbonio_nginx_vhost** — `zmproxyconfgen` + reload nginx  
6. **webmail_https** — verificação HTTPS `mail.{dom}`

**SSH:** `traefik_ssh_host = root@10.10.10.114` (chave root VM112→CT114).

---

## 10. Sincronização de artefactos (canais)

| Canal | Caminho | Direção |
|-------|---------|---------|
| **Produção VM112** | `/opt/ibytera-mail-portal` | Target deploy |
| **Workspace Proxmox** | `/root/workspace/projects/ibytera-mail-portal` | Dev + git |
| **Obsidian** | `/root/obsidian-infra/carbonio/ibytera-mail-portal` | Documentação |
| **LAPTOP** | `.../LAPTOP/` → `C:\LAPTOP\projetos\` | scp Windows |
| **GitHub** | https://github.com/itecnologys/ibytera-mail-portal | Versionamento |

```bash
# Executar no host que tem o código fonte (Proxmox ou VM112):
./scripts/sync-all.sh
```

**Excluídos do rsync:** `.venv`, `node_modules`, `secrets/`, `.env`

---

## 11. Segredos e integrações SaaS

| Ficheiro | Integração |
|----------|------------|
| `secrets/cloudflare.token` | Cloudflare API (conta Ibytera) |
| `secrets/llm.env` | Gemini, fallback chain |
| `secrets/kimi.env` | Kimi (opcional) |
| `.env` | IP mail, SMTP local, URLs ntfy |

**Notificações:** SMTP `127.0.0.1:25` + ntfy `10.10.10.115:8091` / https://ntfy.ligbox.com.br

---

## 12. Frontend — rotas SPA

| Path | Componente |
|------|------------|
| `/` | `LigboxHome` (landing) |
| `/onboard` | Redirect → `onboard.ligbox.com.br` (ver **Spec 016**) |
| `/admin` | `DomainAdmin` |
| `/termos`, `/privacidade` | Legal |
| `/sobre`, `/planos`, `/suporte`, … | `LegalStub` |

### 12.1 Handoff portal → wizard (Spec 016)

**Problema:** `ligbox.com.br` e `onboard.ligbox.com.br` não partilham `localStorage`.

**Solução:** tripla redundância — `?planned_email=`, cookie `.ligbox.com.br`, localStorage.

Documentação completa: [`SPEC_016_PORTAL_WIZARD_HANDOFF.md`](SPEC_016_PORTAL_WIZARD_HANDOFF.md)

**Regra:** usar sempre `redirectToOnboard(email)` no portal; build falha se regressão (`npm run check:handoff`).


### 12.3 Build wizard-only (`main-wizard.jsx`) — rotas obrigatórias

Host: **`onboard.ligbox.com.br`** · build `npm run build:wizard`

| Path | Componente | Obrigatório |
|------|------------|-------------|
| `/admin` | `DomainAdmin` | ✅ Sim |
| `/admin/forgot-password` | `ForgotDomainPassword` | ✅ Sim |
| `/assist/{session}` | `App` (ASM) | ✅ Sim |
| `?ticket=` | `ClientTicketPortal` | ✅ Sim |
| default | `App` (wizard) | ✅ Sim |

**Bug P1 (2026-06-19):** omitir `/admin` fazia «Portal de gerenciamento» reabrir o wizard no passo Concluído. Ver KB `20260619_WIZARD_PORTAL_ADMIN_ROUTE_FIX.md`.

### 12.2 Passo DNS — Zona DNS Ligbox (Spec 017)

**Passo 2 do wizard:** escolha entre trazer DNS para a **Zona DNS Ligbox** (Cloudflare) ou manter no registrador actual.

No modo externo, após clicar «Manter no provedor actual», a UI mostra **dois blocos**: zona DNS actual (público + Cloudflare) e registos necessários Ligbox.

Documentação completa: [`SPEC_017_PORTAL_WIZARD_DNS_STEP.md`](SPEC_017_PORTAL_WIZARD_DNS_STEP.md)

**Endpoint chave:** `GET /api/onboarding/dns/current-zone/{domain}`

---

## 13. Ligação futura VM113 (Ligbox Ops)

| Evento (planeado) | Origem VM112 | Destino VM113 |
|-------------------|--------------|---------------|
| `account.created` | webhook | Desk / auditoria |
| `infra.pending` | webhook | Alertas ops |
| `infrastructure/status` | API read | Dashboard tenant `112` |

**Regra:** VM112 **fora** do Docker Compose VM113.

---

## 14. Documentos relacionados

| Documento | Local |
|-----------|--------|
| Família produtos | `docs/product/FAMILIA_PRODUTOS_LIGBOX_MAIL.md` |
| **Handoff portal→wizard (Spec 016)** | `docs/architecture/SPEC_016_PORTAL_WIZARD_HANDOFF.md` |
| **Passo DNS wizard (Spec 017)** | `docs/architecture/SPEC_017_PORTAL_WIZARD_DNS_STEP.md` |
| Traefik onboard | `docs/TRAEFIK_ONBOARD.md` |
| Release marca UI | `docs/releases/RELEASE_20260604_PRD6_MARCA_UI.md` |
| Backlog | `BACKLOG.md` |
| Ligbox Ops spec (VM113) | `ligbox-ops-platform/docs/architecture/` (a criar) |

---

## 15. Inventário rápido (comando)

```bash
# Serviços portal + carbonio
systemctl is-active ibytera-mail-portal carbonio-nginx carbonio-appserver

# Domínios
/opt/zextras/bin/zmprov gad

# Registry portal
ls -la /var/lib/ibytera-mail-portal/domains/

# CT114 SNI
ssh root@10.10.10.114 cat /root/traefik/haproxy-mail-sni/maps/sni_vm112.lst
```

---

*Gerado em 2026-06-04 a partir do estado live da VM112 (`mail.dratcoin.com`).*
