# User simulation (Python, API)

Background-friendly cycles that call the same REST endpoints as the React app. Staff bootstrap companies and users; portal customers and channel actors create traffic; agents handle tickets. After each cycle, a JSON/Markdown report lists failures so you can fix and re-run.

## Prerequisites

1. **Stack running** — e.g. `docker compose up` from the repo root; API at `SIM_API_BASE` (default `http://localhost:3001`).
2. **Hybrid seed** — at least:
   - Admin (seed: `docker compose exec api npm run seed`)
   - 1–2 staff agents (`role=user`) matching `agent_handler` emails
   - 1–2 companies with portal users matching `end_user` / `technical_user` emails
3. **Portal / web chat channel** — required for `POST /api/v1/portal/messages`.
4. **Email (optional)** — create an email channel; set `SIM_EMAIL_INBOUND_TOKEN` (or let `admin_operator` discover it via channel detail).
5. **Landing chat** — works when Turnstile is unset locally; captcha failures are soft-skipped.
6. **Python 3.10+**

## Setup

```bash
cd user_automation
python -m venv .venv
.venv\Scripts\activate   # Windows
# source .venv/bin/activate  # macOS/Linux
pip install -r requirements.txt
copy .env.example .env   # or cp; edit SIM_API_BASE and password env vars
copy users.example.json users.json
# Edit users.json: emails, persona, password_env_key (or inbound_token_env_key)
```

**Secrets:** Passwords and inbound tokens only in `.env` (gitignored). Manifest references them by key.

## Personas

| Persona | API role | Behaviour |
|---------|----------|-----------|
| `admin_operator` | `admin` | Tickets (assign/priority/escalate/reply/close); create companies, portal users, staff users; discover email inbound token |
| `agent_handler` | `user` (or `admin`) | Tickets + create companies + portal users |
| `end_user` | `company_user` | Short portal intake / follow-ups; closed-ticket negative probe |
| `technical_user` | `company_user` | Detail-heavy portal messages; prefers follow-ups; closed-ticket probe |
| `email_reporter` | *(none)* | `POST /api/v1/inbound/email/:token` |
| `landing_visitor` | *(none)* | `POST /api/v1/landing/chat` (sticky session) |
| `support_seeker` | `company_user` | Alias of `end_user` (older manifests) |

Staff scenarios also create extra companies/portal users during the run (hybrid bootstrap). Created emails are logged in the cycle report; they are not auto-added to the live tick list.

## Run

```bash
# One QA cycle (default), then write report under user_automation/reports/
python -m user_automation --manifest user_automation/users.json --cycles 1 --interval-seconds 10

# Several cycles with jitter
python -m user_automation --cycles 5 --interval-seconds 15 --jitter-ms 500

# Infinite soak (Ctrl+C stops; last cycle report still written)
python -m user_automation --cycles 0 --interval-seconds 60

# Only one random user per cycle
python -m user_automation --cycles 3 --max-users-per-tick 1 --jitter-ms 2000

# Validate credentials / personas only
python -m user_automation --manifest user_automation/users.json --dry-run
```

**Fix loop:** run → open `user_automation/reports/cycle-*.md` → fix product bugs → re-run.

## Reports

Each cycle writes:

- `reports/cycle-YYYYMMDD-HHMMSS-cN.json` — machine-readable errors + bootstrap IDs
- `reports/cycle-YYYYMMDD-HHMMSS-cN.md` — human summary

Scenario failures are captured (continue-on-error); they do not abort the cycle.

## Operational notes

- **Real data** — simulations create companies, users, messages, and may close tickets. Use a disposable dev database.
- **Empty queues** — If there are no open tickets, agent ticket-touch logs a skip and counts as pass.
- **WhatsApp** — not simulated yet; staff replies on WA channels may hit channel-not-connected (environment-dependent).
- **Overlapping load** — start multiple processes with different `--interval-seconds` only if the API can handle it.

## Files

| File | Purpose |
|------|---------|
| `users.example.json` | Template manifest (copy to `users.json`). |
| `.env.example` | Template env (copy to `.env`). |
| `sim_client.py` | Login + authenticated / public HTTP helpers. |
| `personas.py` | Persona ↔ role rules. |
| `scenarios.py` | Per-tick scenario implementations + `RunState`. |
| `runner.py` | Cycles, jitter, continue-on-error, reports. |
| `reports/` | Generated cycle reports (gitignored). |
| `__main__.py` | `python -m user_automation` entrypoint. |
