# Deploy to Portainer This doc sets up the toolkit as its own stack in Portainer, pulled directly from Gitea. It assumes the repo is public or internal-open on your Gitea instance, so Portainer needs no Git credentials to pull it. Repo: `https://primegit.primecontrols-dev.com/m.mabrey/sde-meeting-toolkit.git` ## Step 1: Add the stack 1. Open Portainer. 2. Go to **Stacks**. 3. Click **Add stack**. 4. Name it `sde-meeting-toolkit`. 5. Set **Build method** to **Repository**. 6. Set **Repository URL** to `https://primegit.primecontrols-dev.com/m.mabrey/sde-meeting-toolkit.git`. 7. Set **Repository reference** to `refs/heads/main`. 8. Set **Compose path** to `docker-compose.yml`. This is the default path; the file sits at the root of the repo. 9. Leave **Authentication** off. The repo does not need credentials to pull. ## Step 2: Set environment variables `.env` is not in the repo on purpose; it holds secrets and is listed in `.gitignore`. `docker-compose.yml` reads each setting through `${VARIABLE_NAME}` substitution instead of a literal `env_file`, so it works whether the value comes from a real `.env` next to the file (local and Docker Desktop use) or from Portainer's own stack settings (Git-pull use, where no `.env` file exists). Portainer's stack editor has its own **Environment variables** section, below the repository settings. Add each of these as a name and value pair. | Name | Value | |---|---| | `ANTHROPIC_API_KEY` | The company API key. | | `APP_USERS` | Comma-separated `user:password` pairs, for example `alice:pass1,bob:pass2`. Leave blank for no login. | | `APP_USERNAME` | Leave blank unless you use the legacy single-login mode instead of `APP_USERS`. | | `APP_PASSWORD` | Leave blank unless you use the legacy single-login mode. | | `RATE_LIMIT_MAX` | `20` | | `RATE_LIMIT_WINDOW_MS` | `300000` | | `TOKEN_LIMIT_PER_USER` | `0` (off). Set a positive number only if you decide to turn the quota back on. | | `TOKEN_USAGE_FILE` | `./data/token-usage.json` | | `MOCK_AI` | `false` | Portainer passes these to Compose as substitution values for the `${VARIABLE_NAME}` references in `docker-compose.yml`. No `.env` file needs to exist on the host for this to work. ## Step 3: Deploy 1. Click **Deploy the stack**. 2. Wait for the build to finish. The image is small; the app has no external dependencies to install. ## Step 4: Verify 1. Go to **Containers**, find `sde-meeting-toolkit`, and open **Logs**. 2. Confirm the log reports: - `ANTHROPIC_API_KEY loaded: AI draft button is live.` - Either `Login required: N named user(s) configured.` or `No login required: ...`, matching what you set in `APP_USERS`. - `No per-user token quota: TOKEN_LIMIT_PER_USER is unset or 0 (unlimited, feature on the back burner).` 3. Open the container's mapped address in a browser (port `5173` by default, per `docker-compose.yml`). Confirm the toolkit's landing page loads. 4. If you set `APP_USERS`, confirm the browser asks for a login before the page loads. 5. Try the AI draft button on the Field Problem Workshop tool and confirm it returns a real draft. ## Redeploying after a code change 1. Push the change to the Gitea repo (`git push`) from your machine, same as always. 2. In Portainer, open the `sde-meeting-toolkit` stack. 3. Click **Pull and redeploy** (or the equivalent update action in your Portainer version). Setting up a Gitea webhook to trigger this automatically is possible later, but is not set up yet. For now, redeploy manually after each push. ## The data folder `docker-compose.yml` mounts `./data:/app/data` so the per-user token quota file survives a restart, if that feature is ever turned back on. Portainer creates this folder under the stack's own directory on the host. With `TOKEN_LIMIT_PER_USER=0`, nothing is written there today; the mount is harmless and already in place for when it's needed.