# HANDOFF — Sales Trainer > Another AI should be able to resume without chat history. ## Branch / repo / deploy - Repo: `~/Gitea/Sales Trainer/` — **git repo, remote = Gitea**. - Remote: `https://git.moreminimore.com/kunthawat/sales-trainer.git` (GITEA_TOKEN via credential helper; never committed). - **Live deploy:** `https://moreminimoreapps-saletrainer.ahkhwd.easypanel.host` — EasyPanel, auto-redeploys from Gitea on push to `main` via webhook (≈3 min). Dockerfile ships prebuilt `frontend/dist/` (no npm in image). LLM vars set in EasyPanel env. ## What this is Corporate multi-user **sales-training simulator**: admins create persona groups from a product/service/idea (โฟกัส "สินค้า/บริการ/ไอเดีย"), app auto-generates **15 customer personas** (5/tier A/B/C) via LLM; trainees pick a **scenario (social / พบหน้า)**, chat 1:1 one-shot to close a sale; a **per-turn + final judge LLM** evaluates feelings and scores/coaches. Vue SPA + Flask API + filesystem JSON storage (no SQL). i18n TH/EN. No self-registration (admin provisions). ## Roles - **super_admin** (bootstrap `admin`) — full recipe (secret persona fields) + tenant admin. - **admin** — manages groups/users, sees personas with **secret fields stripped** (IP protection). - **user** (trainee) — trains against personas, own board. ## Current state — COMPLETE core + hardened All backend + frontend built. **11 test suites green** (mock LLM): ```bash cd backend uv run python scripts/test_m0.py # auth/roles/no-self-reg uv run python scripts/test_m1.py # group create + role visibility uv run python scripts/test_setup.py # first-time admin setup (email+password+ToS) uv run python scripts/test_security.py # path traversal / IDOR / XSS uv run python scripts/test_scenario.py # 2 scenarios (social/f2f_call), recontact default uv run python scripts/test_e2e.py # full flow -> won via judge uv run python scripts/test_ip_protection.py # secret fields hidden from admin uv run python scripts/test_saas_tenant.py # tenant isolation + rate-limit + audit uv run python scripts/test_user_journey.py # idea-flow end-to-end uv run python scripts/test_variant.py # clone-persona-from-persona uv run python scripts/test_resume_decision.py # resume + per-turn LLM decision # run backend (serves SPA from frontend/dist) cd backend && uv run python run.py # Flask :5001 ``` ## Key behaviors (implemented) - **One-shot:** 1 persona = 1 chat per user; result final (won/lost). `SessionStore` enforces. - **Resume:** unfinished session resumes on re-entry — **no** scenario re-pick (same session+scenario). - **Win/loss = per-turn LLM judge** (`Simulator.evaluate_turn`): every customer reply is evaluated → `{mood, decision(buy|walk|pending), score_delta, reason}`; session ends when decision = buy/walk. **Not** fixed keywords. - **2 scenarios only:** `social`, `f2f_call`. Unknown → social. - **Recontact = persona trait** (not a scenario): chats normally, then at turn ≥ 2 a time-lapse system note ("⏳ ผ่านไป 2-3 สัปดาห์…"), then re-engages warmer. - **Persona variant:** `POST /api/groups//personas//variant` — new persona (new id) that **locks** pains/objections/levers/tolerance/special/recontact/goal/budget/difficulty/tier/product **but varies** identity (name/profession/age/location/background/personality/opener). Lets a trainee re-practice the same challenge (one-shot is per-persona). UI button on finished personas. - **Auto 15 personas** on create; no "เพิ่มเติม" button (TARGET=15, retry up to 3× + accept ≥ 8 so real LLM under-count doesn't 500). - **IP protection:** `SECRET_PERSONA_FIELDS` (pains, objections, negotiation_levers, opener, tolerance, rootCause, resolutionConditions) stripped for `admin`; full only for `super_admin`. - **SaaS Phase 1–3 done:** tenant isolation (`g.org_id` + `assert_tenant`), login/chat rate-limit, audit log (`data/audit/audit.jsonl`), org plan/seats/active model + `PATCH /api/admin/orgs/`, ToS consent on setup, org-scoped signed expiring CSV export (5-min HMAC). - **Reduce raw JSON in UI:** `list_groups` returns lightweight summary (persona_count, no full array); persona detail rendered as readable form/cards (pain = line-by-line, not `[object Object]`). ## Credentials / data (testing) - Bootstrap super-admin `admin` / `1234` → first login forces email + new password + ToS consent. - Live test users: `testadmin` / `1234` (admin), `testuser` / `1234` (user). - A test group "CRM ระบบจัดการลูกค้า" exists on live (user keeps it; will delete it themselves). - **LLM key is a placeholder on local `.env`** (`replace_me`). Real analyze/chat needs a real `LLM_API_KEY` (+ `LLM_PROVIDER`/`LLM_MODEL`/`LLM_BASE_URL`) in EasyPanel env then redeploy. ## Environment / gotchas - **Python 3.11 only** (system default 3.14 incompatible). Use `backend/.venv` or `cd backend && uv run python …`. - **Tooling guard crash:** commands whose first token is `./.venv/bin/python` trip a lifecycle guard → always use `uv run python`. Prefix `PYTHONPATH=` when needed. - **Frontend build:** `cd frontend && npm run build` (works even with allowScripts restrictions). Commit `frontend/dist/` with `git add -f` (it's gitignored otherwise); the Dockerfile needs it. - **Deploy pattern:** commit + push → webhook auto-deploys in ~3 min. Cannot run Docker locally (no Docker on this Mac) → test with nginx/`python http.server` or `uv run python run.py`. - **No remote push without asking** unless it's the established auto-deploy cadence. - `search_files`/`read_file` sometimes misdetect files as binary (e.g. `users.py`, some `.vue`); use `terminal` + `sed -n 'N,Mp' ` or `awk` for those. ## Wire-authorized / known-limits - Chrome/Vivaldi drivable via computer-use; current model (DeepSeek V4 Flash) reads screenshots imperfectly, and window-edge resize to a 320px viewport didn't land — **mobile visual QA at 320/500px still needs the user's eyes** (open live URL on phone, or DevTools device toolbar). Responsive CSS (640px, single-column, `flex-wrap`, `.btn-back`) is present + deployed. ## Next actions / backlog (also docs/FUTURE_WORK.md) - Real `/legal` page (setup links to it), billing/payments, per-tenant storage volume, compressed persona recipe, export-token polish. - Mobile visual polish per user feedback on real device. - Deeper: letting admins bulk-import personas, analytics drill-down per persona variant. ## Related docs - `docs/PLAN.md`, `docs/SAAS_PLAN.md`, `docs/FUTURE_WORK.md`. - `docs/engineering-log.md` + `docs/engineering-log/2026-08-09-idea-flow-qa-deploy.md` (this session: idea-flow UX, 2-scenario + recontact trait, live QA + auto-deploy, per-turn LLM judge, persona variant, 15-persona auto-gen).