Ctrl K
ComunidadGuías…

SETUP.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Local workstation setup

Bootstrap a fresh machine (laptop, ephemeral VM, codespace) to run, test, and deploy Managoat. Should take ~10 minutes on broadband.

## Prerequisites

| Tool       | Why                                                                 | Install                                                                 |
| ---------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `mise`     | Pins Elixir/Erlang to the exact versions in `.tool-versions`.       | `brew install mise` (macOS) · `curl https://mise.run \| sh` (Linux/WSL) |
| `gh`       | GitHub CLI for cloning and PRs.                                     | `brew install gh && gh auth login`                                      |
| `psql`     | Client for the dev/test Postgres.                                   | Comes with `brew install postgresql@16`. Match the server major (16): an older `pg_dump` refuses a newer server, which is the backup drill.                   |
| Docker *or* native Postgres 16 | One way to host the dev/test database.                  | `brew install --cask orbstack` (or Docker Desktop), or `brew install postgresql@16 && brew services start postgresql@16`. |

After installing `mise`, [activate it in your shell](https://mise.jdx.dev/getting-started.html#activate-mise):

```bash
# zsh
echo 'eval "$(mise activate zsh)"' >> ~/.zshrc

# bash
echo 'eval "$(mise activate bash)"' >> ~/.bashrc
```

Open a new shell so `mise` is on the PATH.

## 1. Clone

```bash
gh repo clone managoat/managoat
cd fountain
```

## 2. Install the toolchain

```bash
mise install
```

This reads `.tool-versions` and installs the pinned Erlang/OTP and Elixir versions (~5 min on first run, cached after). `.tool-versions` pins the *local* toolchain only; production runs the release image built from the repo-root `Dockerfile`, whose base image pins its own Erlang/Elixir (see [Production parity reference](#production-parity-reference)).

Verify:

```bash
elixir --version
# Erlang/OTP 28 ...
# Elixir 1.19.2 (compiled with Erlang/OTP 28)
```

## 3. Hex + Rebar (one-time, per-toolchain)

```bash
mix local.hex --force
mix local.rebar --force
```

## 4. Postgres

Pick **one** path:

### Option A — Docker (recommended for ephemeral machines)

```bash
docker compose up -d postgres
```

Brings up Postgres 16 on `localhost:5432` with role `postgres`/`postgres` (already running your own Postgres? set `POSTGRES_HOST_PORT` in `.env` to publish elsewhere). `mix setup` creates `fountain_dev` itself. (`docker compose up` with no service name also starts Managoat — see [self-hosting](docs/self-hosting.md).) Stop with `docker compose down`; data persists in the `postgres_data` volume.

### Option B — Native Postgres

If you already run Postgres locally (e.g. `brew services start postgresql@16`), make sure a `postgres` superuser role exists with password `postgres`:

```bash
psql -h localhost -U "$USER" -d postgres \
  -c "CREATE ROLE postgres WITH LOGIN SUPERUSER PASSWORD 'postgres'"
```

(Skip if you already have it.)

Both paths satisfy the default `DATABASE_URL` baked into `config/dev.exs` and `config/test.exs`. To override, export `DATABASE_URL` before any `mix` command.

## 5. Dependencies and database

```bash
mix deps.get
mix setup        # deps.get, acp.bundles (the pinned adapter bundles) + ecto.setup for the dev DB
```

For the test DB:

```bash
MIX_ENV=test mix ecto.create
MIX_ENV=test mix ecto.migrate
```

## 6. Environment variables

`config/runtime.exs` reads a `.env` at the repo root. Start from the local-dev subset:

```bash
cp .env.example .env
```

| Variable | Purpose |
|---|---|
| `DATABASE_URL` | The Postgres connection (the default matches both options in step 4). |
| `MASTER_SECRETS_KEY` | The platform master key for envelope encryption. Make one with `openssl rand 32 \| base64 \| tr '+/' '-_' \| tr -d '='`. |
| `SPRITES_TOKEN` | The Sprites sandbox platform; without a provider every conversation fails. |
| `GITHUB_OAUTH_CLIENT_ID` / `_SECRET` | GitHub sign-in, optional. |
| `SMTP_HOST` and `EMAIL_FROM` | Email over SMTP, optional. Unset, mail is off and accounts self-verify. |

The full list is [docs/configuration.md](docs/configuration.md).

## 7. Run

```bash
mix phx.server   # http://localhost:4000
mix test         # full suite
```

`mix precommit` runs the local gate; its stages, and what CI runs on top, are in [CONTRIBUTING.md](CONTRIBUTING.md#before-you-push). Run it through the pinned toolchain (activate mise, or `mise exec -- mix precommit`); it refuses a different Elixir.

## Production parity reference

The release image is built from the repo-root `Dockerfile`, and `deploy/` holds the portable Kubernetes baseline (decisions/0032). The Erlang/Elixir toolchain is pinned in three places, and a toolchain bump must update all of them:

| Where                      | What pins the toolchain                                              |
| -------------------------- | -------------------------------------------------------------------- |
| `.tool-versions`           | `erlang` / `elixir` lines (local dev via mise)                       |
| `Dockerfile`               | the `FROM hexpm/elixir:<elixir>-erlang-<otp>-...` build-stage base image |
| `.github/workflows/ci.yml` | `elixir-version` / `otp-version` in the `erlef/setup-beam` step      |

The lockstep is enforced by `apps/fountain/test/fountain/toolchain_lockstep_test.exs` — if the three pins disagree, the test suite goes red.

## Troubleshooting

- **`role "postgres" does not exist`** — see step 4. Either `docker compose up -d postgres` or create the native role.
- **Compile warnings about `OpentelemetryPhoenix` / `OpentelemetryEcto`** — these deps are `:prod`-only; `apply/3` is used to defer symbol resolution. If you see warnings, you're probably on stale `_build`; `rm -rf _build deps && mix deps.get && mix compile` to reset.
- **mise installs Erlang from source and it's slow** — that's normal on first run. Subsequent installs (and ephemeral machines that share a mise cache) reuse the build.
- **Tests fail with connection pool timeouts** — check that `config/test.exs` still sets `pool_size: 20`, and lower `--max-cases` on a machine with many cores.
- **Tests fail with `rate_limited` errors** — shouldn't happen: `config/test.exs` sets `rate_limit_test_isolation: true`, which keys `FountainWeb.Plugs.RateLimit` buckets by the calling test process instead of a shared IP. If you see this, check that the flag is still set in `config/test.exs` (it's a correctness guard — don't remove it) and that your test isn't issuing enough requests from one process to legitimately exceed a bucket's limit.