# Arquitetura ## Visão geral ```mermaid flowchart TB subgraph Internet B[Browser
Chrome/Edge/Firefox] end subgraph Host["Host / VPS (Docker)"] T[Traefik
:80 / :443] W[web-client
nginx + build Babylon] P[ws-proxy
Bun WS↔TCP] DOC[docs
nginx] subgraph O["openmu (1 processo all-in-one)"] CS1[ConnectServer :44405
cliente original, sem uso] CS2[ConnectServer :44406
protocolo estendido] GS[GameServers 0..2
:55901-55906] LS[Login / Friend / Guild
in-process] CH[ChatServer :55980] AP[Admin Panel + /api :8080] end PG[(PostgreSQL 18
rede interna)] end B -- HTTPS --> T B -- WSS --> T T -- play.* --> W T -- ws.* --> P T -- admin.* --> AP T -- docs.* --> DOC P -- TCP 44406 --> CS2 P -- TCP 55902/04/06 --> GS GS --- LS O -- backend (internal) --> PG ``` ### Redes Docker | Rede | Membros | Observação | |---|---|---| | `edge` | reverse-proxy, web-client, ws-proxy, docs, openmu | publica só 80/443 (Traefik); o openmu não publica nenhuma porta do jogo (D15) | | `backend` (`internal: true`) | postgres, openmu | sem acesso externo; PostgreSQL **nunca** é publicado | ## Componentes | Componente | Imagem/origem | Papel | |---|---|---| | **Browser** | — | Baixa o cliente Babylon de `play.DOMAIN`, abre WebSocket em `ws.DOMAIN`. | | **ws-proxy** | `services/game-proxy` (Bun, código `clients/web/proxy`) | Recebe `ws://…/?host=H&port=P`, valida contra `ALLOW_TARGETS`, abre TCP e repassa bytes. Também tem tracker/journal (SQLite em volume), relay de "band"/"ping" e clima sintético. Não termina TLS (o Traefik termina). | | **ConnectServer** | OpenMU | Lista de servidores e endereço do GameServer. Um por tipo de cliente (44405 original, sem uso; 44406 protocolo estendido, usado pelo web). | | **GameServer** | OpenMU | Mundo do jogo. Cada servidor tem um endpoint por tipo de cliente. | | **LoginServer / FriendServer / GuildServer** | OpenMU | No all-in-one rodam no mesmo processo (não há portas próprias). | | **ChatServer** | OpenMU :55980 | Messenger in-game (salas de chat). | | **Admin Panel** | OpenMU :8080 (Blazor) | Setup, contas, configuração, plugins, mapa ao vivo, logs, API `/api` (API keys). Login próprio com bootstrap via `OPENMU_ADMIN_*`. | | **PostgreSQL 18** | `postgres:18.6-alpine` | Schemas `config`, `data`, `friend`, `guild`, `admin`… O OpenMU usa o superusuário para criar banco e roles na 1ª inicialização. | | **Traefik v3** | `traefik:v3.7.13` | Roteamento por host, TLS Let's Encrypt (prod). Provider de **arquivo** (sem `docker.sock`). | | **docs** | `nginx:1.30.5-alpine` | Serve `docs/` (esta documentação + `index.html`). | ## Fluxos ### Browser → WSS → Proxy → OpenMU 1. `GET https://play.DOMAIN/` → Traefik → nginx (bundle estático; `VITE_*` definidos no build). 2. JS abre `wss://ws.DOMAIN:443/?host=openmu&port=44406&session=` → Traefik (TLS) → ws-proxy:3000. 3. Proxy confere `openmu:44406` em `ALLOW_TARGETS` (senão **403**) e abre TCP na rede docker. 4. CS devolve `127.127.127.127:55902` (valor fixo, ignorado); o cliente reconecta em `?host=openmu&port=55902` (política "auto"/`gs=cs`). 5. Login (`LoginLongPassword`, versão 20404, SimpleModulus/Xor32), pacotes `*Extended`, seleção de personagem, jogo. O cliente desktop foi removido do projeto (D15). ### Dentro do OpenMU ``` ConnectServer ──(registro de endpoints)── GameServer │ PlayerActions / PacketHandlers (plugins) ▼ GameLogic ── PlugInManager (pontos de extensão, nossos MuCustom.*) │ ▼ Persistence (EF Core, contexts por role) │ ▼ PostgreSQL ``` ## Decisões de arquitetura (resumo — detalhes em [decisions.md](decisions.md)) 1. **All-in-one + Traefik**, não o deployment distribuído (documentado pelo upstream como quebrado). 2. **Upstreams como git submodules** fixados por SHA; nada de `latest` implícito. 3. **Camada custom do servidor via `DOTNET_STARTUP_HOOKS`** → zero patches no core. 4. **Cliente web em build de produção** (nginx), não o dev server do compose upstream. 5. **Traefik sem docker.sock** (provider de arquivo com templates) — menos superfície. 6. **Proxy WS com allowlist obrigatória** — o padrão upstream é relay aberto. 7. **Web no protocolo estendido** (CS 44406, GS 55902/04/06) — D16; nenhuma porta do jogo publicada (D15).