# Arquitetura Interna Visão de como o código está organizado. A aplicação segue o padrão [The Elm Architecture](https://github.com/charmbracelet/bubbletea) (Model–Update–View) da biblioteca Bubble Tea. ## Estrutura de pastas ``` . ├── cmd/ │ └── main.go # Ponto de entrada; inicia o programa Bubble Tea ├── internal/tui/ │ ├── model.go # Struct Model, ConfigValues, carga de defaults, InitialModel/Init │ ├── steps.go # Enum das etapas do assistente │ ├── update.go # Lógica de transição (Update) por etapa │ ├── view.go # Renderização (View) por etapa │ ├── form.go # Componente genérico de formulário (FormStep/FormField) │ ├── cmds.go # Mensagens (Msg) e comandos assíncronos (tea.Cmd) │ ├── docker.go # Wrappers de chamadas ao binário docker │ ├── config.go # Geração e gravação de config.toml e envs │ └── styles.go # Paleta de cores e estilos Lip Gloss ├── config.toml # (gerado em runtime; ignorado no git) ├── envs # (gerado em runtime, vproxy) └── Makefile # Build multiplataforma e publicação no S3 ``` ## Componentes principais ### `Model` ([model.go](../internal/tui/model.go)) Estado único da aplicação. Campos relevantes: - `currentStep` — etapa atual do assistente. - Estado de progresso/flags: `dockerInstalled`, `downloadDone`, `finishedFile`, `finishedDockerRun`, e os respectivos erros. - Um `FormStep` por etapa de formulário (`loginForm`, `wireguardForm`, `appForm`, `serverForm`, `dbForm`, `certForm`). - `configValues` (`ConfigValues`) — acumula os valores de todos os formulários, agrupados por seção. `loadConfig()` define os **valores padrão** e, se houver um `config.toml` no diretório, sobrescreve com o conteúdo dele (usando `BurntSushi/toml`). `InitialModel()` constrói todos os formulários com esses defaults. ### Etapas ([steps.go](../internal/tui/steps.go)) `step` é um enum (`iota`) que define a ordem do assistente. O `Update` faz o dispatch com base em `currentStep`. Ver [fluxo.md](fluxo.md) para o detalhamento. ### Update ([update.go](../internal/tui/update.go)) `Update` trata primeiro mensagens globais (`Ctrl+C`, `WindowSizeMsg`, tick do spinner) e depois delega para um handler por etapa (ex.: `updateCheckDocker`, `updateDownloadImage`, `updateRunDocker`). As transições de etapa acontecem ao concluir formulários (`done == true`) ou ao receber mensagens de conclusão dos comandos assíncronos. Constantes importantes ficam no topo do arquivo: - `imageName` / `wireguardImageName` — imagens no registry privado. - `configPath` (`config.toml`) / `wireguardConfigPath` (`envs`). ### View ([view.go](../internal/tui/view.go)) `View` monta a tela com cabeçalho fixo, corpo dependente da etapa e rodapé de ajuda. Usa `AltScreen`. Cada etapa tem um método `viewXxx` ou reutiliza o `View()` do formulário. ### Formulário genérico ([form.go](../internal/tui/form.go)) `FormStep` agrupa vários `FormField`. Suporta os tipos texto, senha, número e seleção. `Update` cuida da navegação entre campos (`Tab`/setas) e retorna `done = true` quando o `Enter` é pressionado no último campo. `Values()` devolve um `map[string]string` indexado pelo `Id` de cada campo — é isso que alimenta o `ConfigValues`. ### Comandos e mensagens ([cmds.go](../internal/tui/cmds.go)) Toda operação bloqueante (chamar `docker`, escrever arquivo) é encapsulada em um `tea.Cmd` que roda em goroutine e devolve uma `Msg` ao loop do Bubble Tea: | Comando | Ação | Mensagem de retorno | | ----------------------------- | ------------------------------------- | --------------------------- | | `CheckDockerCmd` | `exec.LookPath("docker")` | `DockerCheckedMsg` | | `DownloadImageCmd` | `docker login` + `pull` (app) | `ImageDownloadFinishedMsg` | | `DownloadWireguardImageCmd` | `docker login` + `pull` (vproxy) | `ImageDownloadFinishedMsg` | | `GenerateConfigFile` | grava `config.toml` | `ConfigFileMsg` | | `GenerateWireguardConfigFile` | grava `envs` | `ConfigFileMsg` | | `RunAppContainer` | `docker run` (app) | `DockerRunMsg` | | `RunWireguardContainer` | `docker run` (vproxy) | `DockerRunMsg` | | `TickCmd` | tick da barra de progresso | `TickMsg` | ### Camada Docker ([docker.go](../internal/tui/docker.go)) Funções utilitárias que invocam o binário `docker` via `os/exec`: - `EnsureNetwork` — cria a rede `app-dono_app` se necessário. - `RunAppClienteContainer` / `RunWireguardDockerContainer` — montam os argumentos do `docker run`, removem container homônimo prévio e verificam o status `running`. - `verifyContainerRunning` — inspeciona o status e, em falha, anexa os últimos logs. - `removeExistingContainer`, `PullImage`, `ImageExists`, `PushFileToContainer`. ### Estilos ([styles.go](../internal/tui/styles.go)) Paleta de cores e estilos Lip Gloss reutilizados na View (títulos, cursor, ajuda, erros, barra de progresso, seleção). ## Dependências - `charm.land/bubbletea/v2` — runtime TUI (loop Model/Update/View). - `charm.land/bubbles/v2` — componentes (`textinput`, `spinner`). - `charm.land/lipgloss/v2` — estilização. - `github.com/BurntSushi/toml` — leitura do `config.toml` para defaults. ## Observações para manutenção - **Porta:** o `config.toml` grava `port = 8080` fixo; a porta do formulário só afeta o mapeamento de host no `docker run`. Ver [configuracao.md](configuracao.md). - **Credenciais:** o login do registry é coletado uma vez e reutilizado para baixar a imagem do vproxy. - **Rede:** o nome da rede é a constante `networkName` (`app-dono_app`) em `docker.go`; usar sempre a constante ao referenciá-la.