Commit Graph

21 Commits

Author SHA1 Message Date
Macky
55759a3a50 fix(api): group create read product from multipart form (bug: 'provide product info' when no file attached)
The GroupBuilder sends the create form as multipart/form-data (FormData). The code
decided JSON vs form by checking  — when no file was attached,
request.files was empty/falsy, so it tried get_json() on a multipart body and lost the
product field -> 400 'provide product info' even though the user filled the product name.

Fix: branch on the Content-Type (multipart/form-data -> request.form) instead of
request.files. Added a regression test (multipart create with product only -> 201).
Verified live: multipart product-only create now returns 201.
2026-08-08 09:49:24 +07:00
Macky
88892be1d9 i18n(th): professional, natural Thai; make Users button prominent
- Rewrite TH translations to professional/natural Thai (e.g. app 'ระบบฝึกทักษะการขาย'
  instead of 'ตัวฝึกขาย', 'บุคคลต้นแบบ' for persona, tiers 'พร้อมตัดสินใจซื้อ',
  'จุดอ่อนที่ควรฝึกเพิ่มเติม', 'ปิดการขายได้/ไม่ได้' for won/lost, etc.)
- Users button in admin overview now solid sky-blue (was faint .soft gray) so it's visible.
2026-08-08 08:01:08 +07:00
Macky
acba183dc1 style(ui): polish admin overview + close-rate progress bar; rebuild dist 2026-08-07 22:53:58 +07:00
Macky
e5a59dbc5c docs: record 3-tab UI build-out (admin dashboard + date filter, personal dashboard, training difficulty, settings) 2026-08-07 22:36:43 +07:00
Macky
b05907ae62 feat(ui): 3-tab UI per spec — admin dashboard + date filter, personal dashboard, training w/ difficulty, settings profile
Tab 1 Admin overview (/): aggregate stats + DATE FILTER (?from&to), hardest personas,
admin quick actions (Users / + Add product).
Tab 2 My dashboard (/my/board): per-user win/lose/session summary (works for admin too).
Tab 3 Training (/training): product list w/ status + persona count; admins see all groups
(draft->analyze/edit), trainees see ready->personas; persona list shows DIFFICULTY (1-5
stars); admins get a Manage-personas button.
Settings (/settings): profile (name/email) via new PATCH /api/auth/profile + change
password + language.
Backend: analytics date filter; profile endpoint; /api/me/board + /api/chat/sessions
opened to any authed user.
Rebuilt frontend/dist.
2026-08-07 22:35:49 +07:00
Macky
ac35be8906 feat(ui): 3-tab layout (Admin overview / My dashboard / Training) + Settings page
- App.vue: top tab bar (Admin overview [admin], My dashboard, Training) + Settings icon
- router: / = admin overview, /my/board, /training, /settings; non-admin '/' -> /my/board
- New views: Training.vue (pick ready product group -> personas), MyBoard.vue (win/lose +
  sessions summary), Settings.vue (change email/password, language)
- Backend: allow /api/me/board + /api/chat/sessions for any authenticated user (so the
  My dashboard tab works for admins too), not just 'user' role
- i18n EN/TH keys; rebuilt frontend/dist
Verified: build ok, /api/me/board + /api/chat/sessions + /api/groups all 200 for admin.
2026-08-07 22:07:16 +07:00
Macky
aec596d1d6 docs: record real 'wrong password after logout' fix (verify resolves username OR email) 2026-08-07 21:02:23 +07:00
Macky
3bc23997e2 build(frontend): refresh committed dist (username login + setup flow)
The committed dist was stale (older build without email-resolving + username login).
Rebuild locally and commit the fresh SPA so EasyPanel serves the correct login/setup
flow. Verified fresh dist references username/must_setup/setup.
2026-08-07 21:00:43 +07:00
Macky
1867a1aac8 fix(auth): login resolves by EITHER username or email
Root cause of 'wrong password' right after logout->login (no redeploy): after first-run
setup sets an email, users naturally type their EMAIL in the login field, but verify()
only looked up by USERNAME -> user not found -> 'invalid credentials' shown as wrong
password. Now verify(ident) = get_user_or_none(username) OR by_email(ident). Verified:
login by username (200) and by email (200) both work with the new password.

Tests: m0/setup/e2e all pass.
2026-08-07 21:00:15 +07:00
Macky
7d778d780d docs: record login-after-setup root cause (deployment data persistence) 2026-08-07 20:21:00 +07:00
Macky
334ef4e00c fix(Docker): require persistent DATA_DIR volume; add VOLUME + README data-persistence warning
Root cause of re-login failing after first-run setup: on EasyPanel/w/o a volume, the
container's /app/backend/data (users, incl. the changed admin password) is wiped on every
recreate, so logging back in with the new password fails. Added:
- ENV DATA_DIR=/app/backend/data (explicit) + VOLUME declaration in Dockerfile
- README 'Data persistence' section: must mount a persistent volume to /app/backend/data

Verified: backend + live server login>setup>relogin-with-new-password works (200); the
failure is deployment data persistence, not login logic.
2026-08-07 20:20:42 +07:00
Macky
273fe7dae5 Fix: language toggle didn't re-render page
Add :key="i18n.locale" to <router-view> so every view re-evaluates
i18n.t() when the locale changes, reliably updating all text (TH/EN).
2026-08-07 20:20:33 +07:00
Macky
9c646173ca docs: record final Docker fix (prebuilt dist, no npm in image) in engineering log 2026-08-07 19:47:15 +07:00
Macky
c19b23d44d fix(Docker): ship prebuilt frontend/dist, drop npm from image (removes 'vite not found')
The Vue SPA is now built locally and its frontend/dist/ committed (force-added).
Dockerfile is a single-stage runtime: copy prebuilt dist + python:3.11 + Flask.
No node/npm inside the image -> deterministic, no npm/esbuild postinstall flakiness.
To update UI: edit src, npm run build, commit frontend/dist/.
2026-08-07 19:46:20 +07:00
Macky
4827481da3 docs: record Docker 'vite: not found' fix (NODE_ENV root cause) in engineering log 2026-08-07 19:28:55 +07:00
Macky
681561c22a docs: update account flow (username admin/1234 + forced setup) in README/HANDOFF/engineering-log 2026-08-07 18:04:18 +07:00
Macky
e8a95bf561 Add username-based login + mandatory first-time admin setup; push-ready
- User id/login = username (was email). Email is a separate settable field.
- Default admin: username admin / password 1234, must_setup=True.
- Login forces /setup on first login: set email + change password, then clears must_setup.
- New /api/auth/setup endpoint; JWT sub = username; admin routes use username.
- Frontend: Login uses username, router guard forces /setup, new Setup.vue (email + new
  password + confirm), i18n EN/TH.
- Tests: test_setup.py added; all suites adapted (m0/m1/routes/security/setup/e2e) PASS.
2026-08-07 17:56:59 +07:00
Macky
eadf4f727a docs: record reviewer-drive security fixes (mask sales_kit/report, ready-gate) in engineering log 2026-08-07 16:10:02 +07:00
Macky
ce6076f7f4 [verified] Apply independent-reviewer suggestions: mask sales_kit/report to trainees, ready-gate get_persona
Responding to the requesting-code-review independent reviewer (passed:true, zero blocking issues):
- get_group: hide sales_kit + report from trainees (they contain latent pain analysis)
- get_persona: add status==ready gate for trainees (parity with list_personas)
- Extend test_security.py with latent-leak + non-ready-gate assertions; all suites pass
2026-08-07 16:09:42 +07:00
Macky
ff0f680090 [verified] Security hardening + UX/UI polish
Security (requesting-code-review pipeline + independent reviewer):
- Fix path traversal on file upload (basename sanitize + resolve-containment)
- Fix IDOR: org + owner scoping on all group/chat routes (_authorize_group/_get_owned_group),
  hide other users' personal groups in listings
- Remove XSS via v-html in Chat task (text interpolation)
- Add test_security.py (traversal + cross-user denial) — all pass

UX/UI (ui-ux-pro-max + frontend-dev-verification):
- Global: focus rings, 44px touch targets, hover/press transitions, input focus glow,
  prefers-reduced-motion, skeleton loaders, empty states, back links, spinner
- Login: password toggle, autocomplete, spinner, disabled-when-empty
- Cards lift on hover; dashboard skeleton + empty state; analyze button spinner

All backend tests pass (m0/m1/routes/security/e2e); frontend builds; served SPA verified via curl.
2026-08-07 16:00:43 +07:00
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