Files
sales-trainer/docs/PLAN.md
Macky c3d31c06e2 Sales Trainer v0.1: corporate sales-training simulator (Flask+Vue, 15 personas, chat simulator, judge, analytics)
- Auth/roles (no self-reg), admin user provision, JWT
- Analyze: sales kit + initial pain-fit from form/upload
- Persona generator: 15 personas (5/tier) w/ pain variety, negotiation, init mode, channel, latent/revealable, wrong_text special
- Chat simulator: per-mode initiation, one-shot, hidden signals, judge-LLM debrief+coaching
- Trainee loop: win/lose board, weak-areas, user-generated personas
- Admin analytics; EN+TH Vue SPA served by Flask
- Deploy: Dockerfile, docker-compose, README, eng-log + HANDOFF
- Tests (mock LLM): m0/m1/routes/e2e all pass
2026-08-07 15:31:06 +07:00

32 KiB
Raw Blame History

Sales Trainer — Plan & Architecture

App platform for Sales Training. Users develop customer personas with pain points from uploaded files + a natural-language description, then chat with simulated customers to practice closing a sale. Informed by two codebases:

  • MiroFish (~/Gitea/MiroFish) — original full-stack CrowdSight engine (Flask + Vue, OASIS, Zep, persona/report/chat).
  • hermes-brain-and-tools (~/Gitea/hermes-brain-and-tools) — clean-room CrowdSight plugin (seed → ontology → graph → environment; profile generator; durable workflow; report contract; social simulation).

This app is a standalone web app (not a Hermes plugin) with its own login/auth, deployable via Dockerfile/EasyPanel (the user's established pattern).


1. Product goals

  1. Input: setup form (product / customer segment / description) AND/OR upload files (.pdf/.md/.txt). Product info is used primarily to extract pains as the raw material for persona generation — it is just initial grounding.
  2. Analyze: extract value propositions, features, pricing anchors, target profile, and an initial pain-fit. A generated persona is reusable across products in the same/similar category — it need not be locked to the exact uploaded product.
  3. Create persona pool: generate 15 personas (5 × intent tier A/B/C), each marked with a buying tier, a set of pains (varied, not all product-solvable), negotiation levers, and an initiation mode (customer-initiated vs seller-initiated). Channel: Facebook / LINE.
  4. Standard report: human-readable analysis report (per persona: background, pains, objections, price sensitivity, buying signals, revealable/latent fields) — downloadable.
  5. Sales Simulation (chat): trainee chats 1:1 with a persona (one-shot). The persona reacts realistically: negotiates, stalls, and refuses to buy unless the trainee actually resolves the persona's specific pain(s). On a result, the app reveals the pain and why the close succeeded/failed (short debrief + coaching).
  6. Training loop: track each user's wins/losses; analyze the personas a user tends to lose against and generate new harder/variant personas (or manual form) to keep training.

2. Persona design (core requirement)

2.1 Intent tiers (23 levels) — REQUIRED

Tier Name Behavior
A Ready-to-buy (ตั้งใจซื้อ) Has budget + authority + urgency. Short close window, but still expects the seller to confirm fit & handle 12 objections. Won't buy if the offer clearly misses their need.
B Unsure / educating (ไม่แน่ใจ) Researching/considering. Needs discovery, trust-building, proof, comparison, and a clear reason to act now. High chance to stall or go silent.
C Not interested but has pain (ไม่สนใจแต่มี pain) Unaware of the category/value, budget-constrained, or skeptical. Strong resistance, but has a real, unresolved pain — the ONLY path to a close is surfacing and resolving that pain.

2.1b Tier counts

  • 5 personas per tier15 personas minimum per project (3 tiers × 5).
  • Each persona is a distinct, realistic individual — no two share the same background/income/personality combination.

2.2 Persona variety (REQUIRED) — every persona gets:

  • Background (life story / situation that justifies their behavior)
  • Income & occupation (varied across personas: salary, e.g. employee / freelancer / SME owner / executive / student / homemaker)
  • Age group & lifestyle (varied: age ranges, family stage, living situation, habits)
  • Personality & temperament (e.g. skeptical, analytical, impulsive, cautious, price-haggler, relationship-driven, impatient, distrustful)
  • Communication style (tone, vocabulary, formality, emoji usage, sentence length)
  • Goal when entering the chat + objections + budget + decision timeline
  • Pains (14), each with: description, root need, and the specific condition(s) the seller must satisfy to resolve it.

Consistency rule: persona demographics (age band, occupation, lifestyle, income) must be consistent with the product's target user (from the sales kit / product data), and the additional description / scenario field acts as a framing constraint for persona creation (e.g. "product targets SME restaurants in Bangkok" → all 15 personas fit that world, with sensible income/lifestyle spread).

2.3 Realism rules (from user)

  • Customers never buy easily. Every close requires "earning" it.
  • All tiers can lose — including Ready-to-buy (A). A customer walks away (no sale) if the conversation is genuinely bad — e.g. rude/aggressive language, ignoring their needs, pushy pitching. Even a customer who desperately wants the product will refuse if the seller violates basic decency or trust. "Wanting it" never overrides "bad experience."
  • They negotiate (price, timeline, scope, add-ons).
  • They refuse / end the chat if the seller fails to address their pain.
  • Each persona has hidden pains the seller must discover (ask questions), not just pitch.

2.3a Negotiation — ALL tiers (REQUIRED)

Every persona bargains over concessions/benefits, at every tier:

  • Price reduction (discount ask),
  • Freebies / add-ons / bundling,
  • Delivery / fulfillment timeline (especially for made-to-order / production goods),
  • Scope adjustments, payment terms, guarantees, etc. The seller must respond to negotiation realistically — give value in exchange, not just give in. The specific negotiable leverage each persona will push on is defined in the persona card.

2.3b Pain variety (REQUIRED)

  • NOT every pain aligns with the product. Persona pains may be:
    • Directly solvable by the product (the clear win),
    • Partially solvable / nearby (the product helps but doesn't fully close it — seller must manage expectation / bundle / reframe), or
    • Unrelated/unsolvable by this product (a genuine red herring — seller must recognize it and redirect rather than force a fit).
  • This mirrors reality: real customers rarely have exactly the pain a product solves. The seller must diagnose which pain is which and only claim what the product truly delivers.

2.3c Chat initiation — TWO modes (REQUIRED)

The simulation supports two initiation modes, set per persona (a persona is either one or the other):

  • Customer-initiated (ลูกค้าทักก่อน): for products/brands marketed to drive engagement (e.g. cars, food, retail). The customer opens the chat; the seller responds.
  • Seller-initiated (ฝ่ายเราเปิดการขายก่อน): for products/services sold proactively / outbound (e.g. insurance, B2B services). The customer does NOT message first — the seller must open the sale. The simulator gives the seller an opening task to start the conversation with a cold/warm lead, and the persona reacts accordingly.

Each persona card declares which mode applies (and, for customer-initiated, includes the persona's opener; for seller-initiated, the persona's initial mood/receptiveness).

Note: this supersedes any earlier "customer always messages first" rule. Initiation is per-case: some personas are customer-initiated, some are seller-initiated.

2.3d Special tier-3 case — "wrong text / lost interest" (REQUIRED, ≥1 in tier C)

  • At least one tier-C persona is designed as a false lead: their opening message makes them appear ready to buy (e.g. "I need this, tell me the price"). But once the seller responds, the persona immediately reveals lost interest and wants to end the conversation ("never mind, forget it") — yet deep down the pain still exists.
  • To close: the seller must not take the "forget it" at face value; they must gently re-engage, rebuild a moment of connection, and surface the still-live pain without being pushy. High difficulty, frequent refusal — it tests resilience + empathy + non-pushy discovery.

2.3e Channel context (REQUIRED)

  • The simulated chat is presented as a real messaging thread. Primary channels: Facebook and LINE. A persona/case declares which channel it happens on (affects the look, and can color tone — e.g. LINE more casual, FB page vs Messenger).
  • Other channels optional later; v1 ships Facebook + LINE.

2.4 Persona lifecycle & one-shot rule (REQUIRED)

  • 1 persona ↔ many users: a persona is a shared playable asset; any user who has not yet chatted it may practice on it.
  • 1 user ↔ 1 chat per persona max (one-shot): a user can chat a given persona only once — the outcome is final and that persona is "used" for that user. It cannot be re-chatted/replayed by the same user. (Reels/retry against it is not allowed.)
  • To practice again on a similar customer, the user must generate a new persona (2.5).

2.5 Persona sources & generation (REQUIRED)

  • Admin-created baseline pool: admin/upload-generated personas form the shared pool that new users can pick from and practice on.
  • User-generated personas: after practicing, a user can generate their own persona to train on, in two ways:
    1. Weak-area generation (4 in feature list): auto-analyze the personas this user tends to lose against → generate a new, harder/variant persona targeting that weakness, as a "lock" to overcome it; or
    2. Manual form: the user describes the persona they want to practice (target profile, situation, difficulty level) and the system generates it.
  • User-generated personas are private to that user (unlike the admin pool).

2.6 Data exposure by view (REQUIRED)

  • Approve/edit view (admin): full persona data — pains, income, personality, negotiation levers, hidden details. Admin sees everything to review/edit/approve.
  • Select/chat view (trainee): only the persona's name + basic info one would plausibly know up front (profession, age group, channel, initiation mode, product context). Hidden: pain, income, personality, budget, negotiation levers — anything you couldn't know without talking. Revealed only after the conversation ends (win/lose + debrief).
  • Win/lose status: the user can always see which personas they've won vs lost vs not yet tried.

3. App architecture

┌────────────────────────────────────────────────────────────┐
│  Vue 3 Frontend (port 3000)                                │
│  Login · Dashboard · Project setup · Report · Chat view     │
└───────────────▲────────────────────────────┬───────────────┘
                │ HTTP/JSON (JWT)            │
┌───────────────┴────────────────────────────▼───────────────┐
│  Flask Backend (port 5001)                                 │
│                                                            │
│  auth/        → register, login, JWT, per-user isolation, ROLES    │
│  api/         → projects, uploads, personas, report, chat, groups  │
│  services/    → analyzer · persona generator                        │
│                → sales_kit (product facts + initial pain-fit)       │
│                → report builder                                     │
│                → sales_simulator (chat engine)                      │
│  storage/     → filesystem JSON per user (no SQL DB)                │
│  llm_client/  → OpenAI/DeepSeek/custom OpenAI-compatible calls      │
└────────────────────────────────────────────────────────────────────┘

3.0 Roles & permissions (multi-user corporate)

Role Can do
Super Admin Manage all users, assign roles, manage org-level persona groups, view all data + analytics.
Admin (Manager) Create/edit/delete persona groups (define a product/offer + its personas), manually edit any persona, manage users in their scope, view analytics.
User (trainee) Cannot create groups. Only selects an existing persona group and practices (chat) on its personas; sees own results.
  • Org model: organizationuserspersona_groupsprojects/sessions.
  • Persona group = a reusable packaged scenario: product definition (sales kit) + the 15 personas generated for it. Admins build groups and may edit/re-analyze them later (groups are editable; regenerate is allowed; admin can hand-edit any persona field).
  • A trainee's "project" is a training session bound to a group + a chosen persona.

3.0b Registration (confirmed)

  • No self-registration. Admin creates users and sends invites (email/account-creation). Only Super Admin and Admin can provision accounts. Roles: Super Admin / Admin / User (no Trainer).

  • Repo root: ~/Gitea/Sales Trainer/

  • Stack: Flask 3 + Vue 3 (Vite) + JWT auth + filesystem JSON persistence + OpenAI-compatible LLM.

  • LLM: reuse the provider-agnostic pattern from MiroFish (llm_client.py): configurable LLM_PROVIDER / LLM_BASE_URL / LLM_MODEL_NAME / LLM_API_KEY via .env. Supports OpenAI, DeepSeek, or any OpenAI-compatible custom model (base URL + model name overridable).

  • Persistence: per-user data/<user_id>/projects/<project_id>/… JSON (mirrors MiroFish/Hermes durable file approach). No external DB needed for v1.

3.1 Data flow

  1. Setup (admin) → create a persona group: form (product/segment/description) + upload files (+ channel & initiation-mode preferences).
  2. Analyze (background, async) →
    • Sales Kit extracted from input (what we sell, features, pricing, value prop, target, use cases) mainly for pain extraction (reusable across same/similar category);
    • Personas generated (15 personas w/ tier, pains, background, negotiation levers, initiation mode, channel, latent/revealable fields).
  3. Approve/Edit (admin) → review full persona data; edit any field; approve pool.
  4. Report (background, async) → structured report assembled from personas (downloadable; full data).
  5. Chat → a trainee picks a persona (one-shot) → real-time conversational close attempt, per the persona's initiation mode.
    • Each message: persona responds; the simulator also returns an internal state update (tier, pain-resolution progress, trust, buying-signal flags) — kept hidden.
    • On close or refusal, the chat terminates with a debrief that reveals latent fields.
  6. Training loop → record win/lose; weak-area analysis; generate-new-persona (lock or manual).

4. Services detail

4.1 analyzer (Sales Kit extraction + initial pain-fit)

Input: setup form with:

  • Product (what it is) — required,
  • Initial customer segment (optional),
  • Additional description / scenario (optional framing for persona creation),
  • OR upload files (.pdf/.md/.txt) carrying all of this — user may skip the form entirely.

Decision logic (clear/simple): if files are uploaded, parse them for product + target + pains; if the form is also filled, the form's explicit fields win and file text fills the gaps (and is still analyzed for extra context / pain-fit). If only files → derive everything from files. If only the form → use the form.

Output (JSON): productName, category, valueProps[], features[], pricing (budget anchors), targetAudience (incl. segment from form), useCases[], competitors[], objectionHandlers[], and — critically — initialPainFit[]: the analyzer's first-pass judgement of which pains the product can plausibly solve (with evidence/claims from the inputs), so persona pains can be built partly against and partly away from this baseline. scenario/description is preserved as a framing constraint passed to persona generation. This grounds all persona + chat generation so the simulation stays on-product.

4.2 persona_generator

Builds the 15 personas (5 × tier A/B/C) for a given persona group. Prompt engineered to enforce:

  • exactly 5 personas per tier;
  • the required variety fields (background, income/occupation, personality, communication style, goals, budget, timeline, objections);
  • pain variety (2.3b): not every pain is product-solvable — include directly-solvable, partially-solvable, and unrelated pains; use initialPainFit as the baseline;
  • the tier-C "wrong text / lost interest" special persona (2.3d) — at least 1;
  • chat opener for every persona + whether they initiate friendly/blunt/indifferent;
  • initiation mode (customer-initiated vs seller-initiated) and channel (facebook/line);
  • latent vs revealable fields (2.6) so the UI can hide what a real seller wouldn't know;
  • JSON output schema (strict), language follows project language (en/th).

4.2b weak_area_analyzer (win/loss insight → new persona)

  • Tracks each user's per-persona outcomes (won/lost) and their scores.
  • On request, analyzes the user's losses: which tier / initiation mode / channel / pain-type / objection-type / negotiation-style they tend to lose against.
  • Produces (a) a summary insight ("you lose most against seller-initiated, price-hardball persona; you rarely handle discount + delivery-time pressure together"), and (b) a spec to generate a new persona targeting that weakness (as a 'lock' to overcome) — or the user can use the manual persona form instead.
  • A user can also see their win/lose status board (which personas won/lost/not-tried).

4.3 sales_simulator (chat engine) — the heart

State machine per chat session:

READY → (customer or seller opens per mode) TALKING ⇄ (negotiating/objecting/thinking) → CLOSED | REFUSED | TIMEOUT
  • Initiation depends on the persona's mode (2.3c):
    • customer-initiated: the customer sends the first message; the seller responds.
    • seller-initiated: the customer does NOT message first — the simulator gives the seller an opening task ("open the sale"), and the seller must start the conversation; the persona then reacts as a cold/warm lead.
  • Channels: Facebook or LINE (2.3e) — affects presentation + some tone.
  • One-shot (2.4): a user may not start a second session on a persona they've already finished (won or lost). Backend enforces it.
  • Hidden/latent data (2.6): the trainee only ever sees revealable fields during the chat; pain / income / personality / budget / negotiation levers / opener are latent and hidden until the end.
  • Hidden pain state: each persona has hidden unresolved pains. The simulator tracks per-pain resolution. Pitching without discovery does NOT resolve pain.
  • Pain-fit realism (2.3b): since not all pains are product-solvable, the simulator must let sellers mis-diagnose — claiming to solve an unrelated pain must backfire (trust down) or lead down a dead end, while the real (product-solvable) pain stays unresolved.
  • Per message: LLM plays the persona in-character (using persona card + sales kit + chat history + current internal state). Returns:
    • reply (the persona's in-character message),
    • internal: updated { trust, painProgress, buyingSignals, tier, mayRefuse }.
  • Close trigger: the judge-LM decides if the seller has satisfied the pain-resolution conditions (visible+hidden) AND the persona verbally accepts the offer/price. Only then CLOSED.
  • Refuse trigger: if trust collapses, the seller pushes a hard pitch without addressing pain, or after N failed attempts → REFUSED.
  • Negotiation: personas actively counter (price, scope, timeline, freebies, delivery). Seller must handle these on top of resolving pain.
  • Timeout/abandon: persona goes silent if seller is repetitive/low-value.

Internal signals are NEVER shown live. Trust/pain/buying meters stay hidden during the conversation (default) — the trainee reads the customer's words only.

Debrief (on CLOSED or REFUSED) — REQUIRED, shown only at conversation end: reveal the latent fields (pain, income, personality, budget, negotiation levers, hidden opener), then:

  • Keep the summary short, then give coaching: for each message that hurt the score, suggest how the seller should have responded so the trainee understands and can improve.
  • CLOSED: brief note on the persona's pain (what it was) + why it closed.
  • REFUSED: the unaddressed pain(s), where trust was lost, which pain was mis-diagnosed (if any) — each with a concrete "better reply" suggestion.
  • A judge-LM (separate from the persona LLM) produces the score + coaching.
  • Toggle: admin can choose to show live meters per persona group if desired; default hidden.

5. API surface (v1)

Method Path Purpose
POST /api/auth/login JWT login
GET /api/auth/me current user + role
POST/PUT /api/admin/users admin: create users + invite, assign roles (super-admin/admin/user)
GET /api/admin/users admin: list users
POST /api/groups admin: create persona group (product files/description)
GET /api/groups list persona groups visible to role (user: selectable only)
GET /api/groups/<id> get group + personas (admin: full; user: practice view)
POST /api/groups/<id>/analyze admin: trigger analyze (sales kit + 15 personas)
GET /api/groups/<id>/report get/download report
GET /api/groups/<id>/personas list personas (grouped by tier; user sees revealable fields only)
GET /api/groups/<id>/personas/<pid> persona card (admin: full; user: revealable only)
PUT /api/groups/<id>/personas/<pid> admin: hand-edit a persona
POST /api/groups/<id>/reanalyze admin: re-run analyze / regenerate personas
POST /api/groups/<id>/personas/<pid>/chat user: start/send message → persona reply + hidden state (one-shot enforced)
GET /api/groups/<id>/personas/<pid>/session user: session state/history
GET/POST /api/sessions user: my training sessions + debriefs (own results)
GET /api/sessions/<id>/debrief user: end-of-chat debrief (pain + reason + coaching + latent reveal)
GET /api/me/board user: win/lose status board per persona (won/lost/not-tried)
GET /api/me/weak-areas user: analyze which personas I tend to lose against (insight)
POST /api/me/personas/generate user: generate own persona — body: {mode: "weak-area" | "manual", ...spec}
GET /api/me/personas user: list my generated (private) personas + status
GET /api/analytics admin: aggregate trainee analytics (close rate, avg score, hardest personas)

All /api/* except login require Authorization: Bearer <jwt>; data scoped by role + org. Admins call analyze/persona-edit endpoints; trainees read revealable fields + run one-shot sessions + generate their own personas.


6. Frontend views (Vue 3 + Vite)

  1. Login (no self-registration — accounts created by admin)
  2. Dashboard — (admin) persona groups + user mgmt; (user) selectable groups + my sessions
  3. Admin: Group Builder — setup form (product/segment/description) + upload files; pick channel (Facebook/LINE) + initiation-mode mix; trigger analyze → approve/edit the 15 personas
  4. Admin: User Management — no self-registration; create + invite users, set roles
  5. Personas (approve/edit, admin only)full data for all 15 personas; edit any field, approve
  6. Personas (select, user) — win/lose status board + list of available personas; each card shows only revealable info (name, profession, age group, channel, initiation mode, product context)
  7. Report — rendered analysis report + download (admin; full persona data)
  8. Simulation (chat) — Facebook/LINE-style thread. Internal signals + latent fields hidden during chat. Initiation per mode: customer opens OR seller gets an "open the sale" task. One-shot enforced. On end → debrief overlay: reveal latent fields + short summary + coaching (how to improve weak-score replies) + pain + reason + score. Result saved; persona marked won/lost for this user.
  9. Gen persona (user) — generate own persona: weak-area (from my loss analysis) or manual form (describe target persona). Private to the user.
  10. Weak-areas (user) — insight: which personas I tend to lose against + generate-a-lock CTA
  11. Admin Analytics — aggregate trainee results (close rate, avg score, hardest personas).

i18n: en + th (mirrors MiroFish pattern). Role-based navigation (admin vs trainee).


7. Security, config, deploy

  • Auth: JWT (HS256) with password hashing (werkzeug generate_password_hash). Secrets in .env. No raw tokens/keys in UI. No self-registration — only admin-provisioned accounts.
  • LLM credentials: .env only, never shipped/logged.
  • File safety: upload allowed types + size caps; parse text server-side; strip anything executable; keep raw uploads out of any served path.
  • LLM route discipline: the chat + persona gen + judge are the only LLM-touching callers.
  • Deploy: single Dockerfile (python:3.11 + Node 18, build Vue → serve static via Flask or nginx) + docker-compose.yml with .env, per the user's EasyPanel pattern. Local tests via http.server / Flask dev (no Docker on local Mac).

8. Milestones (build order) — ALL COMPLETE

  • M0 — Scaffold & auth: repo, Flask app factory, JWT auth, roles (super-admin/admin/user), user + org store, admin-user creation/invite (no self-registration).
  • M1 — Input & analyze: setup form (product/segment/description) + file upload/parse with precedence rule, sales-kit extraction + initial pain-fit, JSON storage.
  • M2 — Persona groups & persona generation: group model (editable/re-analyzeable); 15 personas (5 × tier) with variety, pain variety, negotiation levers, chat openers, initiation mode (customer/seller), channel (facebook/line), latent vs revealable fields, and the tier-C "wrong text" special case; admin hand-edit persona endpoints.
  • M3 — Report: assemble + render + download report.
  • M4 — Chat simulation: stateful persona chat (per-mode initiation: customer opens OR seller "open the sale" task), Facebook/LINE thread, negotiation, all-tiers-can-lose, close/refuse logic, hidden signals + latent fields, one-shot enforcement, separate judge LLM for scoring, short debrief with coaching (latent reveal + pain + reason + how to improve).
  • M5 — Trainee loop: win/lose status board, weak-area analysis, user-generated personas (weak-area "lock" + manual form), my-sessions.
  • M6 — Frontend polish: login, role-based dashboard, group builder (+ persona approve/edit UI), user mgmt, personas (select view), report, chat UI, debrief overlay, gen-persona, weak-areas, admin analytics dashboard, EN+TH i18n. (SPA served by Flask; verified live)
  • M7 — Deploy & docs: Dockerfile, docker-compose, README, engineering-handoff docs, E2E verification with honest status reporting. (mock-LLM E2E; real-key + Docker pending)

Status: prototype complete + verified with mock LLM. Pending: real-LLM live smoke test and remote Docker/EasyPanel validation (see docs/HANDOFF.md).


9. Acceptance criteria

  1. Multi-user corporate, no self-registration: super-admin/admin create + invite users; roles Super Admin / Admin / User (no Trainer). User (trainee) cannot create — selects a group + practices.
  2. Setup accepts form (product / segment / description) AND/OR uploaded files, with a clear decision rule (form-wins, file-fills-gaps; files-only → derive all).
  3. Analyzer produces sales kit + initial pain-fit; persona demographics (age, occupation, lifestyle, income) are varied AND consistent with product + scenario framing.
  4. → 15 personas (5 × tier A/B/C); admin can edit any persona and re-analyze the group.
  5. Persona group has ≥1 tier-C "wrong text / lost interest" special persona.
  6. Report is human-readable + downloadable.
  7. All tiers can lose — bad conversation (e.g. rude language) = no sale, even for ready-to-buy.
  8. All tiers negotiate concessions (price / freebies / delivery timeline / scope / payment).
  9. Initiation is per-persona mode: customer-initiated (customer opens) OR seller-initiated (seller gets an "open the sale" task). Channels Facebook + LINE. Internal signals + latent fields are hidden during chat; only revealable fields shown.
  10. One-shot rule: a user can chat a persona only once (won/lost = final); the same persona stays playable for other users.
  11. Two persona views: admin sees full data (approve/edit); trainee sees only revealable info (name, profession, age group, channel, initiation mode) — latent fields revealed only after result.
  12. Win/lose status board; weak-area analysis; user-generated personas (weak-area "lock" OR manual form), private to the user.
  13. Debrief is short + coaches: suggests how to improve on weak-score messages; reveals pain + reason. Scored by a separate judge LLM; no speed factor in scoring.
  14. Product data is used primarily for pain extraction; personas are reusable across the same/similar product category.
  15. Admin analytics dashboard aggregates trainee results (close rate, avg score, hardest personas).
  16. Single docker compose up runs the whole app (or EasyPanel build); LLM pickable as OpenAI / DeepSeek / any OpenAI-compatible custom model via .env.
  17. E2E tests pass; honest report of any blocked stages.

10. Confirmed decisions (all from user)

  • Standalone web app (Flask + Vue + JWT), Docker/EasyPanel deploy.
  • Multi-user corporate, no self-registration — Super Admin / Admin / User (no Trainer). Admin creates + invites users.
  • Admin builds/edits persona groups, hand-edits any persona, re-analyzes groups, sees analytics.
  • LLM: OpenAI, DeepSeek, or custom OpenAI-compatible (configurable via .env).
  • 5 personas per tier → 15 min per group.
  • Persona variety: age-group, occupation, lifestyle, income — consistent with product + scenario framing.
  • Internal chat signals hidden, revealed at end; short debrief + coaching (how to answer better on weak-score messages).
  • All tiers can lose; all tiers negotiate concessions.
  • Separate judge LLM for close/refuse + scoring; no speed factor in scoring.
  • Admin analytics dashboard (aggregate trainee results).
  • UI EN + TH.
  • Product user-input via form AND/OR uploaded file with clear precedence; analyzer computes initial pain-fit. Product data mainly for pain extraction — personas reusable across same/similar category.
  • Personas have pain variety (not only product-solvable), demographically consistent with product.
  • Initiation per persona: customer-initiated OR seller-initiated (open-the-sale task).
  • Channels: Facebook + LINE.
  • Two views: admin full data; trainee revealable-only (latent hidden until result).
  • One-shot rule: 1 user = 1 chat per persona; persona shared across users.
  • User-generated personas: weak-area "lock" OR manual form (private).
  • Win/lose board + weak-area analysis.
  • ≥1 tier-C "wrong text / lost interest" persona.

11. Remaining open questions (low-risk; defaults noted)

  • Invite delivery: email link to set password, or admin pre-sets a temporary password? (Default: admin sets temporary password on account creation; optional email later.)
  • Analytics granularity: just group-level aggregates, or drill-down per persona/trainee? (Default: group + per-persona close rate + avg score; per-trainee detail on request.)
  • Scoring weights (beyond dropping speed): pain 40 / trust 30 / objection-handling 30 ok?
  • Persona edit UI: full form for all fields, or JSON editor for power users? (Default: structured form for common fields + JSON for advanced.)

Plan is ready for build. Confirm the low-risk defaults above if you disagree, otherwise I begin M0.