Frontend:
- Add frontend/src/i18n/th-TH.json (913 keys, full parity with zh-CN)
- Register th-TH in i18n entry with native element-plus-secondary Thai locale
- Add Thai option to language selectors, legacy th_TH alias mapping,
and browser locale detection (th* -> th-TH)
- Add common.thai label to all existing locale files
Backend:
- Add backend/locales/th-TH.json (177 keys)
- Accept th-TH in language whitelist, schema regex, and MCP question
- Map th* to Thai language name in LLM prompt language selection
- Apply question language to guess-question prompt template
Dashboard resource endpoints (load_resource, update_resource,
update_canvas, delete_resource) fetched a core_dashboard row by id
alone, with no check that the caller created it. The only gating
decorator verified workspace membership, not per-user ownership, so
any authenticated workspace member could read, rename, or delete any
other member's dashboard by id. list_resource already filters by
create_by, showing dashboards are meant to be private per creator;
this adds the same check to the other four code paths.
Ignore blank names and DESCRIBE metadata headers. Retain partition columns once in their original order, preserve valid hash-prefixed column names, and keep support for extra driver columns.
Refs dataease/SQLBot#1250.
- Add extract_keywords() to LLMService with conversation context support,
using process_stream + start_log/end_log for logging consistency
- Add expand_with_terminology() to expand keywords with synonym matching
- Add fusion scoring in calc_table_embedding(): α * vec_score + (1-α) * keyword_score
- Add calc_keyword_score() with multi-level matching:
table name exact (1.0), comment exact (0.9), comment substring (0.7),
table name partial (0.25-0.5), field comment exact (0.5),
field comment substring (0.4), field name partial (0.3)
- Scoring considers keyword coverage rate to differentiate tables
with different numbers of matched keywords
- Extracted keywords persisted to ChatRecord for reuse across endpoints
- get_terminology_template() supports comma-separated keyword input
with per-keyword matching for higher precision
- Add TABLE_EMBEDDING_ALPHA and TABLE_EMBEDDING_KEYWORD_ENABLED config
- TokenMiddleware/ResponseMiddleware/audit logger use scope['path']
instead of request.url.path for whitelist checks: a crafted Host
header (e.g. x/api/v1/mcp) was concatenated into Starlette's URL
and made protected routes match the /mcp* whitelist entry
- validateEmbedded rejects admin accounts and non-type-4 apps, so a
self-signed token with account=admin can no longer impersonate the
administrator
- Add HostValidationMiddleware rejecting malformed Host headers at the
outermost layer (defense in depth)
- Add regression tests for host validation, whitelist matching and
source-level guards
Co-Authored-By: Claude <[email protected]>