Files
tuio/CLAUDE.md
T
jbandClaude Opus 4.8 ef126eaf61 feat: add build-stamped version with --version flag and TUI header
Introduce tui.Version (defaults to "dev"), stamped at build time via a
VERSION_LDFLAG in the Makefile (-X .../internal/tui.Version=$(VERSION))
across all build targets. main.go handles "--version"/"-v" before
launching the TUI, and the version is shown next to the title in the
header. Docs updated (README + CLAUDE).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:57:05 -03:00

170 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CLAUDE.md
Guidance for Claude Code when working in this repository.
> User-facing docs are in Portuguese (BR): [README.md](README.md) and [docs/](docs/).
> This file is in English and is the technical source of truth for how the code works.
## What this is
A terminal UI (TUI) **installer** for the "App do Dono" **client middleware**. The
middleware runs on a tenant's infrastructure and brokers communication between the
tenant's servers and davinTI's **central server**.
The installer is a guided wizard that: checks Docker → logs into the private registry
→ pulls images → (optionally) sets up a WireGuard tunnel (`vproxy`) when there is no
public IP → collects configuration via terminal forms → generates config files
(`config.toml`, `envs`) → runs the Docker containers.
It is **not** the middleware itself — it only provisions and launches it via `docker`.
## Tech stack
- **Go 1.25**
- **Bubble Tea v2** (`charm.land/bubbletea/v2`) — Elm-architecture TUI runtime.
- **Bubbles v2** — `textinput`, `spinner` components.
- **Lip Gloss v2** — styling.
- **BurntSushi/toml** — read existing `config.toml` for form defaults.
- Module path: `git.davinti.com.br/davinTI/app-dono/tui`.
## Layout
```
cmd/main.go Entry point; starts the Bubble Tea program.
internal/tui/
model.go Model struct, ConfigValues, loadConfig (defaults), InitialModel, Init.
steps.go step enum — the ordered wizard stages.
update.go Update: global keys + per-step dispatch (handlers).
view.go View: header + per-step body + help footer (AltScreen).
form.go Generic FormStep/FormField component (text/password/number/select).
cmds.go Msg types and async tea.Cmd wrappers around docker/file ops.
docker.go os/exec wrappers around the `docker` binary.
config.go Generates & writes config.toml and envs (+ numeric validation).
styles.go Lip Gloss palette/styles.
Makefile Multi-arch build + S3 publish.
```
## Architecture (Model–Update–View)
- **Model** ([model.go](internal/tui/model.go)) holds all state: `currentStep`,
progress/error flags, one `FormStep` per form, and `configValues` (`ConfigValues`)
which accumulates each form's `map[string]string` output by section.
- **Update** ([update.go](internal/tui/update.go)) handles global messages
(`Ctrl+C`, window size, spinner tick) then dispatches on `currentStep` to per-step
handlers. Step transitions happen when a form returns `done == true` or when an
async completion message arrives.
- **View** ([view.go](internal/tui/view.go)) renders per-step.
- **Commands** ([cmds.go](internal/tui/cmds.go)) wrap every blocking op (docker calls,
file writes) as a `tea.Cmd` returning a `Msg`: `DockerCheckedMsg`,
`ImageDownloadFinishedMsg`, `ConfigFileMsg`, `DockerRunMsg`, `TickMsg`.
## Wizard flow
`steps.go` defines the order. See [docs/fluxo.md](docs/fluxo.md) for full detail.
1. `StepCheckDocker` — `exec.LookPath("docker")`. Missing → `StepDockerInstall`
(instructs manual install and exits; **never auto-installs Docker**).
2. `StepDockerLogin` → `StepDownloadImage` — `docker login` + `pull` of the app image.
These registry credentials are **reused** later for the vproxy image.
3. `StepIPQuestion` — "public IP available?"
- **Yes** → jump to `StepAppConfig`.
- **No** → vproxy block: `StepWireguardConfig` → `StepGenerateWireguardFile`
(writes `envs`) → `StepDownloadWireguard` → `StepRunWireguard`.
4. Config forms: `StepAppConfig` → `StepServerConfig` → `StepDatabaseConfig` →
`StepCertConfig`.
5. `StepReview` — shows all collected config; Enter confirms.
6. `StepGenerateFile` — writes `config.toml` (validates numeric fields first).
7. `StepRunDocker` — runs `app-dono-cliente` container.
8. `StepDone`.
### Navigation & error handling
- **Back navigation:** `Esc` returns to the previous *input* step. The Model keeps a
`history []step` stack; `advance(next)` pushes the current input step, `goBack()`
pops. `isInputStep` ([steps.go](internal/tui/steps.go)) gates which steps participate
— action/wait steps (downloads, file gen, container runs) are excluded so back never
re-enters a side-effecting step. `Esc` is handled globally in `Update`; forms don't
consume it. Form values survive going back because the `FormStep`s live on the Model.
- **Retry vs. fix:** transient failures (image pull, container run) offer `r` to re-run
just that command (`q`/other quits). Validation failures (file generation) route back
to the relevant form to correct the value instead of quitting.
## Key constants
In [update.go](internal/tui/update.go):
- `imageName = hub.davinti.com.br:443/app-dono/app-cliente:latest`
- `wireguardImageName = hub.davinti.com.br:443/davinti-vproxy:latest`
- `configPath = config.toml`, `wireguardConfigPath = envs`
In [docker.go](internal/tui/docker.go): `networkName = app-dono_app` (all containers
join this network; created on demand).
## Generated files
- **`config.toml`** — app config, bind-mounted at `/app/config.toml`. If present at
startup it seeds form defaults via `loadConfig`. Generated by `GenerateConfigTOML`.
- **`envs`** — vproxy/WireGuard env vars, passed via `--env-file`. Generated only when
there is no public IP. By `GenerateWireguardConfig`.
Both are gitignored.
## Containers
| Container | Image | Notes |
| ------------------ | -------------------- | -------------------------------------------------------- |
| `app-dono-cliente` | app-cliente | `<host port>:8080`, mounts config.toml + cert dir, `--restart unless-stopped`, runs as host uid:gid. |
| `vproxy` | davinti-vproxy | `--cap-add=NET_ADMIN`, `/dev/net/tun`, `--env-file envs`, only without public IP. |
`seccomp=unconfined` is added to either container when the "Modo Compatibilidade"
(`seccomp_unconfined`) select is `"Sim"` — for old machines.
## Gotchas (read before editing)
- **Port:** `config.toml` always writes `port = 8080` (hardcoded in
`GenerateConfigTOML`). The form's "Porta" value only sets the **host-side** port in
the `docker run` mapping (`<port>:8080`); inside the container the app always listens
on 8080.
- **Network name** is the `networkName` constant (`app-dono_app`) in
[docker.go](internal/tui/docker.go); use it rather than re-typing the literal.
- **Registry credentials** are collected once (login form) and reused for the vproxy
pull — no second prompt.
- Containers run detached and are verified with `docker inspect` for `running`; on
failure the last 20 log lines are surfaced.
## Build & run
```bash
go run ./cmd # run from source
go build -o installer ./cmd # local binary
make build # multi-arch (linux/darwin/windows, amd64/arm64) → ./dist
make build VERSION=2.0.0
make clean
make push S3_BUCKET=<bucket> VERSION=<v> # sync dist/ to S3 (version + latest)
make release S3_BUCKET=<bucket> VERSION=<v> # per-binary copy with OS/arch naming
```
**Versioning:** `tui.Version` ([internal/tui/version.go](internal/tui/version.go))
defaults to `"dev"` and is stamped at build time via `VERSION_LDFLAG`
(`-X .../internal/tui.Version=$(VERSION)`) in the Makefile. `installer --version`
(or `-v`) prints it and exits before the TUI starts; it is also shown in the TUI
header. A plain `go build` leaves it as `"dev"`. The Makefile build rules have no
source deps, so `make build` will not rebuild existing `dist/` artifacts — run
`make clean` first when re-stamping a new VERSION.
Tests (`go test ./...`) cover the pure logic in
[config_test.go](internal/tui/config_test.go) (config.toml/envs generation + numeric
validation) and [form_test.go](internal/tui/form_test.go) (`FormStep.Values()`). The
docker wrappers, Update and View are not unit-tested — verify those by running
`go build ./...` and exercising the TUI manually. Fully running the installer requires
a working Docker daemon and registry access.
## Conventions
- User-facing strings in the TUI are **Portuguese (BR)**; keep new ones consistent.
- Keep code comments and identifiers matching the surrounding style (mixed
English identifiers, Portuguese user messages).
- When adding a wizard step: add it to `steps.go`, a handler in `update.go`, a render
branch in `view.go`, and any new `Msg`/`Cmd` in `cmds.go`.