Pure moves only — zero behavior change, template untouched:
- types.ts (447), utils.ts (51), data/{auth,navigation,practice,mentor,
home,supervisor,icons}.ts, styles/app.css (4690, still global non-scoped
via <style src>)
- App.vue 9006 → 3559 lines; 98 moved declarations verbatim except
export/import syntax
- Built CSS hash identical to pre-refactor (byte-equal styles); reactive
state, computed, watchers, lifecycle and templates all stay in App.vue
- Component-level split deferred to phase two after 2026-07-10 Alpha
- New aihr_knowledge_answer_feedback table; unique (tenant, query_norm,
fragment_id) pair keeps submissions idempotent
- POST /api/knowledge/answer-feedback (fragmentIds array), GET pending-review
list, POST /{id}/review — all under existing auth scope
- Down-voted (question, fragment) pairs are filtered from dbSearch fusion
results; if filtering empties the hit list the original results are kept
with an explanatory caution (never degrade to no-answer)
- Feedback table missing/unreachable → filter silently skipped, search
behavior unchanged (degradation chain preserved)
- SnippetResponse gains optional trailing fragmentId (db hits only; seed
fallback stays null); mobile sopPanel adds 👍/👎 with locked state after
submit, up votes auto-marked reviewed to keep the review queue clean
- /turn accepts optional regenerate+style (serious/gentle/detailed/professional);
regenerate short-circuits before rememberTraineeReply — no round advance,
no trainee reply write, no scoring impact; only same-round coachHint evidence
is overwritten
- Style instruction injected into existing LLM turn prompt; LLM missing/failed
returns original hint with explicit message (no fake data)
- Mobile practice page renders 再严肃/再温柔/更细致/更专业 pills under coach
hints; success replaces text with a style note, failure toasts and keeps
original; old clients unaffected (fields appended)
- Treat 'undefined'/'null' localStorage values as absent; clear incomplete
token/clientId pairs and prompt re-login instead of sending broken headers
- Gate authenticated UI on both token and clientId via isAuthenticated
- Reject login responses missing access_token or client_id