Files
sales-trainer/docs/plan-2026-08-21-ux-saas-redesign.md
Macky 9fd748154d feat: UX/SAAS 12-point redesign
- auth: self-registration (role=user); first-created-user becomes super_admin
- roles: super_admin may promote others; regular admin cannot see super_admin accounts
- products: user-created private groups; admin 'สินค้าขององค์กร' (shared) with hidden/public; users can create groups
- analytics: team + per-user weak areas, close-rate-by-difficulty buckets, 30-day default, weekly trend, trainee table, active users; dashboard redesigned
- files: docx + xlsx upload support (python-docx + openpyxl)
- ui: tabs การฝึก→ผลการฝึก→ภาพรวม; admin lands on ภาพรวม / user on การฝึก; guide in topbar
- consolidate: weak-areas merged into Results (10/page), my-personas merged into Training
- copy: บุคคลต้นแบบ→persona everywhere; clearer add-product form (A/B/C, upload-or-fill)
- report: remove ดูรายงาน UI entry (endpoint kept)

Backend 348 tests pass; frontend build + vitest clean.
2026-08-21 12:28:22 +07:00

8.6 KiB
Raw Permalink Blame History

UX/SAAS Redesign — Plan (2026-08-21)

Owner review of Sales Trainer → 12-point redesign toward a multi-tenant SAAS model. Decisions locked via clarify 2026-08-21.


P0 — Locked decisions

  1. Super admin policy: super_admin MAY promote others to super_admin (operates on trust). The first user created becomes super_admin automatically. Regular admin does NOT see super_admin usernames in the user list and CANNOT change/see them; only super_admin manages admins.
  2. SAAS product scoping: user-created product = private group (owner sees it only, existing owner_user_id model). admin-created product = สินค้าขององค์กร (shared, org-wide). Two clearly separated sections in Training UI.
  3. Difficulty split: 3 buckets — ง่าย (difficulty 12) / กลาง (3) / ยาก (45). Close rate shown per bucket so viewers cannot misread "many wins = good" when trainees pick only easy personas.
  4. Dashboard extras: total sessions + active users + weekly training trend + per-trainee table (each user: sessions · wins · close rate · dominant weak area). Anti-misread priority: the difficulty split must be prominent — never let aggregate wins appear good when wins skew easy.
  5. Report removal: remove the "ดูรายงาน" button + page from the UI only. Keep the /report endpoint + stored report data (non-breaking; admin tooling still works via API).

P1 — Backend changes

B1. Auth / registration (point 1, 5)

  • New POST /api/auth/register (username + password + email) → creates user role="user", seat-checked, in tenant org. No must_setup (password set at signup) unless desired else first-login setup.
  • First-created-user rule: when the platform has zero users, the first registered/created user is promoted to super_admin automatically (bootstrap). When users already exist, default role = user.
  • Keep OAuth path (already role=user).

B2. Role hierarchy (point 4, 5)

  • Allow an existing super_admin to set role="super_admin" on another user via admin update (currently blocked: "provisioned only by bootstrap").
  • list users (admin view): a regular admin MUST NOT see rows whose role == "super_admin". Only super_admin sees all. super_admin can change status/role of any admin; regular admin cannot change admin/super_admin.
  • Ensure role-change rules: only super_admin can grant admin or super_admin; admin grants user only.

B3. Group visibivity / creation (point 6, 7)

  • Allow user (trainee) to create groups → these become private (owner_user_id = self, status = ready after analyze). create_group route: relax require_roles("admin") to allow user with forced owner marker + private visibility.
  • Admin-created group = org-shared สินค้าขององค์กร (no owner_user_id).
  • New visibility field on admin/shared groups for point 7: visibility/published:
    • public (default when shared) → visible to all trainees.
    • draft/hidden → hidden from trainees; admin can still train it (preview mode).
    • Admins always see both. A hidden group is trainable by admin (its sessions flagged preview so they don't pollute trainee analytics — reuse existing previewMode logic).
  • list_visible_to update: user sees (their own private ready groups) + (org shared groups where published/public == true and status == ready). Admin sees all org shared (incl hidden/draft)
    • never other users' private groups (except super_admin).

B4. Analytics (point 3)

  • Default date window = last 30 days (today30 → today). Keep optional from/to override.
  • Team weak areas: aggregate finished trainee sessions → same dimension analysis as per-user weak-areas, but across all org trainees (reuse analyze_weak_areas, feed with all finished trainee sessions).
  • Per-user weak areas: in the per-trainee table (B5) each row carries that user's top weak area.
  • Close rate by difficulty: bucket persona by difficulty 12 / 3 / 45 → per-bucket {plays, wins, losses, close_rate} in overall.difficulty (or top-level close_by_difficulty).
  • Anti-misread: also add an overall breakdown note/flag when bucket win-share skews to ง่าย; UI will emphasize buckets.
  • Remove hardest_personas from analytics response (replaced by weak areas); keep or drop — replace with team_weak_areas.
  • Extra metrics: total_sessions, active_users (distinct trainees with ≥1 session in window), weekly_trend (sessions+wins per ISO week in window), trainee_table (per user: play/win/loss/ close_rate/avg_score/top_weak_area).

B5. File parser (point 12)

  • Support .docx (python-docx) and .xlsx (openpyxl) in parse_document, with size caps + safety.

P2 — Frontend changes

F1. Nav / tabs / landing (point 2, 3, 10)

  • Tab order: การฝึก → ผลการฝึก → ภาพรวม (training first for everyone).
  • Renames: myDashboardผลการฝึก; adminOverviewภาพรวม (admin only tab).
  • Admin landing: after login an admin lands on ภาพรวม (analyze-first). Non-admin lands on การฝึก (train-first). (Router redirect + redirectAfterLogin update.)
  • First-time user with no products → go to add-product form directly.
  • Guide moved to topbar: replace standalone /guide nav entry with a topbar question-mark/guide link + dropdown (role-aware). Keep /guide route for the full page if desired, but entry point = topbar.

F2. Page consolidation (point 3, 4, 5)

  • ผลการฝึก page = MyBoard: weak-areas section at top (before history), then history paginated 10/page. Remove standalone /my/weak-areas page (merge logic in).
  • การฝึก page = Training: product grid (user's own products section, then สินค้าขององค์กร section below), then Persona ของฉัน (private personas) section below product list. Remove standalone /my/personas page (merge logic in).
  • Admin only: manage/edit product routes stay.

F3. Copy / language (point 1, 6, 8, 11)

  • Replace บุคคลต้นแบบ → persona everywhere (i18n EN + TH + docs). Note: user explicitly reversed the old "persona→บุคคลต้นแบบ" standard.
  • "บุคคลต้นแบบส่วนตัว" → Persona ของฉัน / Persona ส่วนตัว (short, clear).
  • Guide rewrite aware of role (user sees train-personas; admin sees manage/analytics/users).
  • Polished, plain-Thai helper text throughout.

F4. Add-product form (point 12)

  • Richer example placeholders for product + segment + description (e.g. "เน้นเพศหญิง รายได้สูง… จำกัดสถานการณ์ที่จำลองได้"). Provide several ready examples.
  • Clear ระดับ A/B/C explanation panel.
  • Upload: accept .pdf .md .txt .docx .xlsx; helper text: "อัปโหลดไฟล์กลุ่มเป้าหมาย/รายละเอียด แทนการกรอกช่องด้านบนได้" (encourage upload-or-fill, not both required).
  • Wording pass: product form labels/descriptions clearer.

F5. Report removal UI (point 9)

  • Remove "ดูรายงาน"/Download report button + GroupReport link from Group edit UI. Keep backend endpoint untouched.

P3 — Deliverables / verification

  • Backend pytest suite green (existing 336 + new tests: register default role, first-user super, super visibility filter, admin promote, user-group creation, draft/hidden visibility, analytics difficulty buckets + 30-day default, docx/xlsx parse).
  • Frontend vite build clean + vitest unit green.
  • Independent reviewer subagent on the diff.
  • Mobile QA at 320×568 + 500×768 after rebuild (per project rule).
  • Docs: engineering-log entry + HANDOFF update.
  • Deploy: Gitea→EasyPanel path, operator approval before push.

Open items / notes

  • Whether first user (username+password) uses must_setup first-login (set email/pw) or full self-signup. Default: self-register sets username+password+email at signup → skip must_setup.
  • Org/tenancy: self-register lands in OAUTH_DEFAULT_ORG-style default org (like OAuth) unless a tenant-invite flow exists. First-user-super_admin is global bootstrap (org-less) — mirror existing super_admin boot semantics.
  • "สินค้าขององค์กร" naming + section split UI confirmed by owner in clarify.