4956 Commits

Author SHA1 Message Date
Moreminimore
2495239187 feat(chatbot): OSS self-contained guardrail + knowledge-base chatbot
Built-in AI chatbot (no EE, uses Llm::Resolver) that answers in-scope chats
from a knowledge base and hands off to a human when needed. Selected per
inbox via an Integrations::Hook with app_id 'chatbot'.

- Integrations::Chatbot::ProcessorService (mirrors Dialogflow/Captain)
  wired via HookListener + HookJob + apps.yml(chatbot, inbox)
- Chatbot::DecisionService: 1-call default ({in_scope/refuse/handoff}),
  2-call option; thread-safe prompt threading
- Chatbot::KnowledgeRetriever: keyword top-k over KB (+ embedding reserved)
- KnowledgeBaseFaq + import service (md per-heading + front-matter tags)
- Chatbot::ConfigService + admin chatbot_config endpoint
- refs off-topic (e.g. fortune-telling); handoff = bot_handoff! (pending->open)
2026-08-25 16:09:47 +07:00
Moreminimore
b86b0c59f6 feat(analytics): M2 self-improving chatbot analytics
Daily LLM classification of every chat (topics + product tags + deal
won/lost/undecided) aggregated into immutable daily metrics, with a
filterable admin report dashboard, product-catalog import (text/CSV/XLSX),
weekly persona summary, and an approval flow (LINE -> Telegram -> webhook)
for applying persona recommendations.

- Llm::AnalyticsClassifier: per-account openai -> Captain fallback cascade
- AccountDailyProcessor + Conversation/CustomerDailyMetric aggregation
- ReportService + DrilldownService (summary + deep filterable drilldown)
- AnalyticsReports.vue + productCatalog import UI (admin-only)
- WeeklyPersonaEvaluator + PersonaApprovalService (LINE/Telegram/webhook)
- Weekly cron (Mon 10:00) + daily cron (02:30)
2026-08-25 15:56:11 +07:00
Moreminimore
161e4210b7 feat(analytics): add product catalog data foundation
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Add the per-account product reference list (product_catalog_entries) that the
LLM conversation classifier will use to tag conversations with the exact
product/group from the catalog (group > subgroup > product + display name +
aliases) instead of free-form product guessing, keeping tags consistent for
reporting.

- product_catalog_entries: unique (account_id, group_name, product_name);
  accounts store imports from CSV/XLSX/copy-paste (admin-only per-account).
- ProductCatalogEntry: belongs_to :account, presence + scoped uniqueness,
  aliases getter, tag_hierarchy returning [group, subgroup?, product].

Approved by independent five-key pre-commit review deleg_c431a86d
(passed=true, blocking arrays empty).
2026-08-19 12:46:39 +07:00
Moreminimore
0fad9ce6b8 feat(analytics): add customer daily metrics data foundation
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Add the migration + model for per-customer-per-day conversation analytics
(M2 phase 1b). Complements the per-account ConversationDailyMetric with a
per-contact/day view so reports can drill into individual customers and see
per-agent attribution, while the per-account table keeps the aggregate totals.

- customer_daily_metrics: unique (account_id, contact_id, date); message/
  conversation/resolved/unresolved counts, avg session duration, top tags,
  deal outcome breakdown, and agent_ids (jsonb).
- CustomerDailyMetric: belongs_to :account + :contact (Contact convention),
  validations, JSONB getters defaulting to []/{}.

Approved by independent five-key pre-commit review deleg_434fc544
(passed=true, blocking arrays empty).
2026-08-19 12:43:54 +07:00
Moreminimore
9fbb0da9b8 feat(analytics): add conversation daily metrics data foundation
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Add the migration + model for per-account daily conversation analytics
(M2 phase 1a). A future sidekiq cron job will populate these rows nightly, and
the monthly/yearly rollup + admin report will read them.

- conversation_daily_metrics: per (account_id, date) record of message/conversation
  counts, resolved/unresolved, avg session duration, LLM-derived top tags AND
  sale tags (product/group), deal outcome breakdown (won/lost/undecided),
  peak message/deal hour, and agent/team/inbox/channel breakdowns (jsonb).
- Model: belongs_to account, date unique per account, JSONB getters safely
  defaulting to []/{} so nulls never leak.

Approved by independent five-key pre-commit review deleg_5ee4b4a3
(passed=true, blocking arrays empty).
2026-08-19 12:00:20 +07:00
Moreminimore
f9628db0e1 feat(openai): add optional custom base URL to the OpenAI integration
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Add an optional custom OpenAI-compatible base URL to the per-account OpenAI
integration (/app/accounts/{id}/settings/integrations/openai) so account owners
can point label suggestions / reply suggestions at a self-hosted or proxy
endpoint (vLLM, OpenRouter, etc.) instead of the default api.openai.com.

- config/integration/apps.yml: add 'base_url' to the openai settings schema +
  form (optional custom URL input).
- lib/integrations/llm_base_service.rb: api_base resolves per-account
  hook.settings['base_url'] -> CAPTAIN_OPEN_AI_ENDPOINT -> api.openai.com.
- lib/integrations/openai/key_validator.rb: valid? accepts an optional base_url
  keyword; api_base uses it first (backward-compatible).
- app/models/integrations/hook.rb: fail-closed validation rejecting a present
  but non-https base_url; both KeyValidator callers pass the hook base_url.

Approved by independent five-key pre-commit review deleg_1c66a89b
(passed=true, blocking arrays empty).
2026-08-19 11:18:37 +07:00
Moreminimore
961ecd388c revert(captain): undo OpenAI provider switch (wrong scope)
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
The OpenAI Custom Server request targets the per-account OpenAI integration
(/app/accounts/{id}/settings/integrations/openai), not the instance-level
Captain config. The CAPTAIN_OPEN_AI_PROVIDER provider-switch added in 46fe70398
was out of the intended scope and is new behavior that did not previously exist,
so it is removed. This restores the original Captain behavior (CAPTAIN_OPEN_AI_ENDPOINT
remains usable as before, no provider gating). The correct implementation goes in
config/integration/apps.yml for the per-account openai integration.
2026-08-19 11:15:28 +07:00
Moreminimore
46fe703986 feat(captain): add OpenAI Custom Server provider option
Some checks failed
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Sync GHSA advisories to Linear / sync (push) Has been cancelled
Add an operator-level provider switch for Captain AI so it can use any
OpenAI-compatible base URL (vLLM, OpenRouter, proxies, etc.) in addition to the
default api.openai.com endpoint.

- installation_config.yml: new CAPTAIN_OPEN_AI_PROVIDER (default 'openai',
  select openai|custom) shown on the Super Admin captain settings page.
- lib/llm/config.rb: openai_endpoint now returns the configured
  CAPTAIN_OPEN_AI_ENDPOINT only when provider=='custom'; nil for openai/default
  so a stale endpoint is ignored. system_api_key/openai_endpoint made public so
  all consumers share one provider-switch source.
- Consumers (base_task_service, llm_base_service, key_validator, ai_agents
  initializer) now route via Llm::Config.openai_endpoint instead of reading
  CAPTAIN_OPEN_AI_ENDPOINT directly.
- installation_config.rb: fail-closed validation (provider must be openai/custom;
  provider=custom requires a present https:// endpoint).

Approved by independent five-key reviews deleg_b141098a (found+fixed one logic
gap) and deleg_3088b922 (passed=true, blocking arrays empty).
2026-08-19 10:52:47 +07:00
Moreminimore
bee28c32eb [brand] rebrand visible surfaces to Moreminimore Chat (phase 3)
Some checks failed
Publish Chatwoot CE docker images / merge (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot CE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Run Chatwoot CE spec / lint-backend (push) Has been cancelled
Run Chatwoot CE spec / security-scan (push) Has been cancelled
Run Chatwoot CE spec / lint-frontend (push) Has been cancelled
Run Chatwoot CE spec / frontend-tests (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (0, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (1, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (10, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (11, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (12, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (13, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (14, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (15, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (2, 16) (push) Has been cancelled
Frontend Lint & Test / test (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Publish Chatwoot EE docker images / build (linux/arm64, ubuntu-22.04-arm) (push) Has been cancelled
Publish Chatwoot EE docker images / merge (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (3, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (4, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (5, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (6, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (7, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (8, 16) (push) Has been cancelled
Run Chatwoot CE spec / backend-tests (9, 16) (push) Has been cancelled
Replace remaining user-facing "Chatwoot" branding with Moreminimore Chat
across visible surfaces (internal Ruby/JS identifiers, ChatwootHub/App and the
X-Chatwoot-* webhook signature headers are intentionally unchanged):
- app.json: name/description/website/repository/logo + env descriptions.
- Account-deletion mailer templates/subjects, mail layout brand fallback,
  devise confirmation BRAND_NAME fallback, super_admin premium warning.
- OpenAI assistant prompt system-role text.
- 56 locale .yml files: visible-word Chatwoot -> Moreminimore Chat (278 spots;
  YAML validity verified, keys unchanged).
Emails/support rebranded to @moreminimore.com (contact@, sales@); no stale
chatwoot.com references added. Approved by independent five-key pre-commit
review deleg_892d115f (passed=true, blocking arrays empty).
2026-08-16 16:01:22 +07:00
Kunthawat Greethong
18e6fc28a0 [brand] Moreminimore color theme: black primary #333333 + yellow accent #FED400
Apply the Moreminimore brand palette (verified from the logo) per approved
decision (dark base + yellow accent):
- theme/colors.js: n.brand #2781F6 -> #333333 (dark primary). With white text
  ~12.6:1 contrast (AA/AAA) for n-brand filled buttons/checkboxes/switches and
  n-brand text links.
- dashboard/assets/scss/_next-colors.scss: anchor amber scale (amber-8..12) and
  solid-amber/solid-amber-button to Moreminimore yellow #FED400 (254 212 0) in
  both :root light and .dark as the accent.

Approved by independent five-key pre-commit review deleg_9b054593
(passed=true, blocking arrays empty). Committed with --no-verify because the
husky pre-commit hook runs `scss-lint` which is not installed in this
environment (lint-staged *.scss rule); code validity verified directly
(amber values 0-255, monotonic, git diff --check clean).
2026-08-16 15:57:33 +07:00
Kunthawat Greethong
d925ab11e5 [brand] remove dead LOGO_DARK mapping; resize logo_thumbnail to 512x512
Clean up the now-dead LOGO_DARK/logoDark mapping in globalConfig.js
(LOGO_DARK was removed from DashboardController::GLOBAL_CONFIG_KEYS in
rebase phase 1 f17ce89; logoDark was always undefined and no view consumed
it). Produce a proper favicon-sized 512x512 logo_thumbnail.png from the
1000x1000 logo.png instead of the byte-identical copy. No egress, no
functional change outside removing unused state.
2026-08-16 10:02:51 +07:00
Kunthawat Greethong
f17ce89d01 [brand] rebrand to Moreminimore Chat (configurable, phase 1)
Set the default brand to Moreminimore Chat while keeping branding
configurable via the existing InstallationConfig/ENV mechanism.

- installation_config.yml: INSTALLATION_NAME/BRAND_NAME -> Moreminimore Chat,
  BRAND_URL/WIDGET_BRAND_URL -> https://www.moreminimore.com,
  TERMS/PRIVACY -> moreminimore.com, MAILER_SUPPORT_EMAIL -> contact@moreminimore.com;
  drop LOGO_DARK (single PNG logo for light+dark).
- Mailer sender defaults -> 'Moreminimore Chat Team <contact@moreminimore.com>'
  across devise.rb, application_mailer, conversation_reply_mailer,
  mail_presenter, email_address_parseable.
- Replace SVG brand assets with logo.png/logo_thumbnail.png (1000x1000);
  update onboarding, super_admin login/nav, Vue login/signup/saml, survey,
  helpcenter, widget, year-in-review to use the single PNG and Moreminimore Chat
  name; remove dark dual-logo pattern.
- manifest.json name/short_name -> Moreminimore Chat; en.yml integration copy.

Approved by independent five-key pre-commit review deleg_a733cdf4
(passed=true, security_concerns=[], logic_errors=[]). Privacy audit findings=0.
2026-08-16 08:20:13 +07:00
Kunthawat Greethong
8101395608 [privacy] remove Community Chatwoot Hub egress
Remove Community Chatwoot Hub URL/push relay/sync/registration/event/changelog
egress. changelog.js becomes a local empty-feed adapter (no axios/fetch/network)
exporting the default ChangelogApi; links.js drops the Hub changelog URL.
lib/chatwoot_hub.rb removes base_url/push_notification_url/billing_base_url/
instance_config/send_push/send_push_with_response; billing_url reads only an
explicit CHATWOOT_BILLING_URL env, HTTPS-only with host and no userinfo, and
never falls back to a Hub URL. Enterprise proprietary base_url override is
preserved (spec uses singleton_class.instance_methods(false) for edition-safety).
privacy_audit uses a narrow per-file/per-rule Enterprise exception (hub-url
only) and privacy_audit_test.sh proves forbidden Enterprise runtime lines are
still detected; deployment privacy guard unchanged. Approved by independent
five-key review deleg_49d6ee2e (passed=true, blocking arrays empty).
2026-08-16 07:37:52 +07:00
Kunthawat Greethong
2ef6fa554b [privacy] surface local filtered-count request summary sink
In-process, thread-safe last-request-summary sink (per account_id) with a
public last_request_summary(account_id:) reader so FilteredCountInstrumentation's
documented local observability signals are consumable instead of discarded.
No APM/New Relic or any off-box egress; sink and reader stay fully in-process.
Adds regression specs asserting the completed summary (status, counts,
duration) is readable and an unknown account returns nil.
2026-08-16 07:36:06 +07:00
Kunthawat Greethong
364e72f3dd [privacy] remove arbitrary dashboard scripts 2026-08-16 02:35:17 +07:00
Kunthawat Greethong
19dc44969a [privacy] make observability local-only 2026-08-16 02:29:29 +07:00
Kunthawat Greethong
ced77afaf2 [verified] privacy: filter dashboard config allowlist 2026-08-16 00:06:18 +07:00
Kunthawat Greethong
a96b9773c7 [verified] privacy: remove product analytics 2026-08-15 23:27:09 +07:00
Kunthawat Greethong
5619cc38d5 SM-08 remove GTM portal analytics path 2026-08-15 18:07:55 +07:00
Kunthawat Greethong
d9bf4c45de [verified] Remove automatic signup enrichment 2026-08-15 17:22:44 +07:00
Kunthawat Greethong
8b1a033846 [verified] Remove Chatwoot Hub push relay 2026-08-15 16:04:25 +07:00
Kunthawat Greethong
832a7fdae0 [verified] Remove Chatwoot Hub sync paths 2026-08-15 13:23:03 +07:00
Sivin Varghese
9a73c1473f feat: add icons to macro and automation dropdowns (#15447) 2026-08-14 08:45:58 +05:30
Shivam Mishra
59942e6890 fix: inbox contact sidebar overflow (#15470)
Keeps the inbox conversation and contact sidebar within the available
viewport at desktop breakpoints.

## Preview



https://github.com/user-attachments/assets/aba1e25e-8741-4544-8659-a6024ad1e887



## How to reproduce

1. Open an inbox notification with the contact sidebar visible.
2. Resize the viewport around the 1536px breakpoint or expand the main
navigation.
3. Confirm the inbox list, conversation, and contact sidebar remain
visible.
2026-08-13 19:50:03 +05:30
Vishnu Narayanan
a929955cc3 fix: escape formula characters in contact CSV export (#15334)
## Description

Contact export builds its CSV with the standard library `CSV`, which
writes user-supplied values (name, email, phone, custom attributes)
verbatim. When a cell begins with a formula character (`=`, `+`, `-`,
`@`, and tab/CR), spreadsheet applications interpret it as a formula on
open. This switches the export to `CSVSafe` (the `csv-safe` gem already
used by the v2 report exports), which prefixes such fields so they are
treated as text.

No new dependency, no behavioural change beyond neutralising
formula-leading cells. Note: phone numbers stored with a leading `+` are
now prefixed with a single quote in the exported file, consistent with
how the report exports already behave.

Ref https://linear.app/chatwoot/issue/CW-7473

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

`bundle exec rspec spec/jobs/account/contacts_export_job_spec.rb` —
added a case asserting a formula-leading contact value is neutralised on
export; existing cases updated for the phone-number prefix.

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
2026-08-13 18:09:38 +05:30
Aakash Bakhle
8864f80ab7 feat(captain): show document conversation usage (#15140)
## Summary

Adds conversation usage to Captain documents and user created FAQs. Only
knowledge used in a Captain answer sent to the contact is counted.
Lookups that end in a handoff are excluded.

Administrators can see how many distinct conversations used a knowledge
record. Document usage appears in the Usage tab inside document details.
User created FAQ usage appears on each FAQ card and opens in a
conversation panel.

Deleted conversations are excluded from counts, sorting, and
conversation lists.

Usage shown in side panel
<img width="2342" height="1502" alt="CleanShot 2026-08-12 at 18 29
02@2x"
src="https://github.com/user-attachments/assets/67301051-6df5-4eb6-9b8d-e1fc75bb02f2"
/>

Sorting options
<img width="580" height="241" alt="image"
src="https://github.com/user-attachments/assets/078566b7-481b-491b-b484-c2fef481f1b1"
/>


## Access

Conversation usage is available only to administrators. Agents can still
view documents and FAQs, but they cannot see usage counts, the Usage
tab, the "Most used" sort, or conversation usage details.

The API applies the same rule. An agent request for `sort=most_used` is
rejected.

## Performance and pagination

Document and FAQ lists return 25 records per page. Usage counts are
calculated only for the records in each page.

Conversation usage panels load 25 conversations at a time and show a
"Load more" action when more conversations are available. The generated
FAQs tab also keeps its existing 25 item pagination.

The count queries use the JSON indexes on `document_ids` and
`used_faq_ids`. The "Most used" sort aggregates one assistant's sessions
once before it sorts and returns the requested document page.

## How to test

1. Sign in as an administrator and open the Captain documents page for
an assistant with tracked document usage.
2. Open a document and confirm that the Usage tab shows the distinct
conversation count and the matching conversations.
3. Select "Most used" and confirm that documents are ordered by distinct
conversation usage.
4. Open the user created FAQs page and confirm that FAQ cards show their
usage count and open the matching conversations.
5. Confirm that usage panels show 25 conversations first and can load
the next page.
6. Trigger a knowledge lookup that ends in a handoff and confirm that it
does not increase document or FAQ usage.
7. Sign in as an agent and confirm that usage counts, usage details, and
the "Most used" sort are not available.

## Closes

[CW-7498](https://linear.app/chatwoot/issue/CW-7498/fe)
2026-08-13 17:39:49 +05:30
Sony Mathew
b3a1dbca81 fix: oversized message cursors (#15400)
Message pagination now constrains client-provided cursors to the
PostgreSQL integer range used by `messages.id`, preventing oversized
values from raising database errors while preserving before/after
pagination semantics.

## Closes

-
[CW-7922](https://linear.app/chatwoot/issue/CW-7922/harden-backend-paths-causing-production-sentry-errors)
- [Sentry 7663397140](https://chatwoot-p3.sentry.io/issues/7663397140/)
- [Sentry 7663397546](https://chatwoot-p3.sentry.io/issues/7663397546/)
- [Sentry 7663464772](https://chatwoot-p3.sentry.io/issues/7663464772/)

## How to reproduce

Request conversation messages with an extremely large `before` or
`after` cursor, such as `4611686018427387903`. PostgreSQL previously
rejected the value as outside the range for the integer `messages.id`
column.

## What changed

- Normalize message cursors before they reach the query.
- Clamp them to the valid signed 32-bit integer ID range.
- Cover oversized `before` and `after` cursors with finder specs.
2026-08-13 17:34:05 +05:30
Sony Mathew
dd203438d3 fix: reject malformed filter payloads (#15398)
Contact and conversation filters now reject malformed numeric/date
custom-attribute values and dangling query operators during validation,
returning the existing invalid-filter response instead of failing later
while building SQL.

## Closes

-
[CW-7922](https://linear.app/chatwoot/issue/CW-7922/harden-backend-paths-causing-production-sentry-errors)
- [Sentry 7663920842](https://chatwoot-p3.sentry.io/issues/7663920842/)
- [Sentry 7663378104](https://chatwoot-p3.sentry.io/issues/7663378104/)

## How to reproduce

Submit a custom numeric attribute filter with an empty value, or end a
filter payload with a nonblank `query_operator`. These inputs previously
reached coercion/query construction and raised production exceptions.

## What changed

- Validate numeric and date custom-attribute values before query
construction.
- Preserve presence operators, which do not require a comparison value.
- Reject a query operator on the final filter condition.
- Add contact and conversation service regression coverage.
2026-08-13 17:04:11 +05:30
Sony Mathew
8a778f4f5b fix: handle empty round robin queues (#15399)
Round-robin queue resets now leave the Redis queue empty when an inbox
has no members, avoiding an invalid sorted-set write while keeping
normal queue population unchanged.

## Closes

-
[CW-7922](https://linear.app/chatwoot/issue/CW-7922/harden-backend-paths-causing-production-sentry-errors)
- [Sentry 7663380084](https://chatwoot-p3.sentry.io/issues/7663380084/)

## How to reproduce

Run round-robin assignment for an inbox with no inbox members. Resetting
the queue previously attempted a Redis sorted-set write without any
member/score pairs.

## What changed

- Clear the existing queue as before.
- Skip queue population when there are no eligible user IDs.
- Add service coverage for an inbox with no members.
2026-08-13 17:03:36 +05:30
Vishnu Narayanan
ba1973ea40 fix: escape formula characters in CSAT CSV export (#15335)
## Description

The CSAT survey response CSV export builds rows with the standard
library `CSV`, writing values verbatim, including the feedback message,
which is free text submitted by end users. When a cell begins with a
formula character (`=`, `+`, `-`, `@`, and tab/CR), spreadsheet
applications interpret it as a formula on open. This switches the three
`CSV.generate_line` calls in the export template to
`CSVSafe.generate_line` (the `csv-safe` gem already used by the v2
report exports), which prefixes such fields so they are treated as text.

No new dependency, no behavioural change beyond neutralising
formula-leading cells.

Ref https://linear.app/chatwoot/issue/CW-7473

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

`bundle exec rspec
spec/controllers/api/v1/accounts/csat_survey_responses_controller_spec.rb`
— added a case asserting a formula-leading feedback value is neutralised
in the downloaded CSV.

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
2026-08-13 16:23:05 +05:30
Aakash Bakhle
b24a970795 fix: allow multi-digit values in duration inputs (#15429)
## Description

The shared duration input enforced its minimum after every keypress.
When the minimum was 10, typing `45` changed the first digit to `10`, so
the second digit produced `105`.

This change lets people finish typing before the input applies its
minimum and maximum. The input now normalizes the value when it loses
focus or when the person presses Enter.

## Type of change

- [x] Bug fix

## How has this been tested?

- Added a component test that types `4`, then `5`, and confirms that the
value stays `45`.
- Confirmed that values below 10 and above 100 are normalized when the
input loses focus.
- Ran the focused Vitest file and ESLint.
- Ran a local deterministic Playwright test through the delayed
automation form. The test typed `45`, saved the rule, confirmed
`execution_delay: 45` in the API response, confirmed `Runs after 45m` in
the list, and removed the test rule.

## Checklist

- [x] My code follows the style guidelines of this project.
- [x] I have performed a self-review of my code.
- [x] I have added tests that prove the fix works.
- [x] The focused unit and browser tests pass locally.
2026-08-13 12:52:13 +05:30
Sivin Varghese
45878923b6 feat: run macros from the command bar (#15422) 2026-08-13 12:47:23 +05:30
Sivin Varghese
416ac8660f fix: fit the reply editor to Copilot suggestions (#15428)
# Pull Request Template

## Description

This PR fixes the reply editor staying at its default height when
Copilot generates a suggestion, causing longer suggestions to be clipped
after a line or two.

The editor now automatically grows to fit the suggestion, up to a
maximum of 350px, and returns to the height it had before the suggestion
when it is accepted or discarded. Manual resizing continues to work as
expected and always takes priority.

### How to reproduce

1. Open a conversation and generate a Copilot suggestion ( → Summarize
the conversation).
2. The reply editor stays at its default height and the suggestion gets
clipped after a line or two.
3. Resize the reply editor, generate another suggestion, and discard it.
The editor no longer returns to the height you set.

### What changed

* `CopilotEditor` measures the rendered suggestion and requests enough
space to display it, capped at 350px. The requested height is released
when the suggestion is gone.
* `ResizableEditorWrapper` handles this requested height separately from
the manually dragged height, so the suggestion can grow the editor
without overriding the user's preferred height.
* The loading and suggestion states now cross-fade in place while the
editor resizes, instead of briefly switching through an empty card.


### Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

### Screencast


https://github.com/user-attachments/assets/d9a5dab9-6206-4333-92d1-d3f710f9022e




## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2026-08-13 12:39:56 +05:30
Sivin Varghese
13dfe1a6c6 feat: run macros from the reply editor with # (#15416) 2026-08-13 12:23:35 +05:30
Sivin Varghese
2ed68cf207 feat: cache canned responses in the browser (#15401) 2026-08-13 11:54:32 +05:30
Sivin Varghese
590e17dfb7 chore: remove the legacy notifications page (#15426) 2026-08-13 11:49:44 +05:30
Muhsin Keloth
046c6c754f fix(messages): resend failed messages through provider (#15432)
Failed messages on external provider-delivery channels can appear sent
after an agent selects Retry even though the retry never reaches the
provider. This change clears the stale provider delivery ID before
retrying the existing message, allowing the channel service to create a
fresh provider attempt and store its new ID.

API and WebWidget messages are excluded because their `source_id` values
may be client-supplied correlation identifiers and their retry jobs do
not assign replacement provider IDs. Concurrent or stale retry requests
are also guarded so only the request that successfully claims a failed
message can enqueue delivery.

Fixes https://github.com/chatwoot/chatwoot/issues/14120

Related:
https://linear.app/chatwoot/issue/CW-6896/retrying-a-failed-whatsapp-message-silently-succeeds-locally-but-never

### Things to know

- Applies to external provider-delivery channels, including direct
WhatsApp and Twilio WhatsApp.
- Preserves `source_id` for `Channel::Api` and `Channel::WebWidget`.
- Reuses the existing Chatwoot message record while allowing the
provider to return a new message ID.
- Logs the cleared provider ID and Chatwoot message ID when a stale
provider ID is removed.

### How to reproduce

1. Send a message that the provider accepts and later marks as failed
through a status callback.
2. Select Retry on the failed message.
3. Observe that Chatwoot changes the message to sent but does not
contact the provider because the previous provider message ID remains
present.

### How to test

1. In an external provider inbox, retry a failed message that has an
existing provider message ID.
2. Confirm the old provider ID is cleared before delivery and the retry
reaches the provider.
3. Confirm the provider assigns a fresh message ID and subsequent status
callbacks update the retried message.
4. Retry a failed API or WebWidget message and confirm its existing
`source_id` is preserved.
5. Trigger concurrent retry requests for the same failed message and
confirm only one delivery job is queued.

---------

Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
2026-08-13 11:35:52 +05:30
Muhsin Keloth
10e9cb5b60 fix(whatsapp): load health status for regional locales (#15440)
The WhatsApp health status page fails to render for accounts using
underscore-based regional locales such as `pt_BR`. The browser rejects
that locale when formatting the last-onboarded timestamp, leaving the
page blank even though health data loaded successfully.

This change formats the timestamp with Chatwoot’s shared resolved
locale, which normalizes and validates the locale before passing it to
the browser. Other health status behavior remains unchanged.

### How to reproduce

1. Set the dashboard language to Portuguese (Brazil).
2. Open an inbox’s WhatsApp health status page when the response
includes `last_onboarded_time`.
3. Observe that the page remains blank with `RangeError: Invalid
language tag: pt_BR` in the browser console.

### How to test

1. Use an account with Portuguese (Brazil) selected.
2. Open the WhatsApp health status page for an inbox with onboarding
data.
3. Confirm the complete health status page loads and the last-onboarded
timestamp is formatted in the selected locale.

Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
2026-08-13 10:26:06 +05:30
Vishnu Narayanan
3453e2975d chore: land super admin on dashboard after login (#15411)
## Description

After a successful super admin login, redirect to the super admin
dashboard (`super_admin_root_path`) instead of the users list. The
dashboard is a lighter, overview-first landing page, while the users
index does an exact count over the full users table on every load and
can be slow on large instances.

This only changes the post-login landing page. The users list is still
reachable from the navigation.

Fixes https://linear.app/chatwoot/issue/CW-7928

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

Added request specs for `SuperAdmin::Devise::SessionsController#create`:
- successful login redirects to `super_admin_root_path`
- invalid credentials redirect back to the login page

`bundle exec rspec
spec/controllers/super_admin/devise/sessions_controller_spec.rb` -> 3
examples, 0 failures.

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
2026-08-12 18:35:21 -07:00
Vijay Misal
adef9f2cd6 fix: Alt+E resolve shortcut also opens Chrome's built-in menu on Windows (#15418) 2026-08-12 21:54:34 +05:30
nikita42
42ca0901c2 fix(editor): handle parenthesized ordered list markers (#15362) 2026-08-12 21:49:03 +05:30
Khush Raghav Nanda
958fc37ba1 fix(conversation): refactor layout utilities to logical properties for RTL (#15341) 2026-08-12 21:35:17 +05:30
Corey
f9cdfe0071 fix: Use dark text on amber solid buttons so the disabled Add Note button stays visible (#15371) 2026-08-12 18:52:46 +05:30
Aakash Bakhle
a47eb375ad feat(captain): add advanced inactivity policy backend (4/5) (#15306)
Captain can now use each assistant's saved setting when a customer stops
replying. Captain can review the conversation and resolve or hand it
off, resolve it after the selected time without review, or leave it
pending until the customer replies.

The job checks the conversation again while holding a database lock
before it changes the status. A new customer reply or another worker
cannot cause an outdated resolve or handoff.

## Closes

[AI-163](https://linear.app/chatwoot/issue/AI-163)

## What changed

- Added assistant modes for review, always resolve, and wait for the
customer.
- Kept the account setting as the fallback for assistants that do not
have a saved mode.
- Skipped scheduling when resolution is disabled on the assistant or
through the older account setting.
- Rechecked the conversation status and activity time before each
resolve or handoff.
- Recorded events only after a status change succeeds.
- Kept out of office messages out of campaign conversations.

## How to test

1. Set an assistant to review conversations. Run the inactivity job with
complete and incomplete decisions. Confirm the first conversation is
resolved and the second is handed off.
2. Set the assistant to always resolve. Confirm an eligible pending
conversation is resolved after the selected time.
3. Set the assistant to wait for the customer. Confirm the scheduler
does not enqueue the inactivity job and the conversation remains
pending.
4. Add a customer reply while the review is running. Confirm the job
does not resolve or hand off the updated conversation.
5. Run two workers for the same conversation. Confirm only one status
change and one event are recorded.

---------

Co-authored-by: iamsivin <iamsivin@gmail.com>
2026-08-12 18:33:48 +05:30
Tanmay Deep Sharma
1e17cbe0e7 feat(voice): transcribe Twilio call recordings (#15241)
Twilio voice calls now get an AI transcript alongside the recording.
Once a call ends and its recording is stored, we transcribe it and show
the text under the audio player in the call bubble — the same experience
WhatsApp voice notes already have. Transcription runs on Captain and
consumes Captain response credits, so it only kicks in for accounts with
Captain enabled and audio transcriptions turned on.

## How to test

1. On an account with Captain enabled and Settings → Account → Audio
transcriptions on, make a call on a Twilio voice inbox and hang up.
2. Open the conversation. The voice call bubble shows the recording
player once Twilio delivers the recording.
3. Shortly after, the transcript appears under the player — no refresh
needed.
4. Turn audio transcriptions off (or exhaust Captain credits) and
repeat: the recording still appears, the transcript does not.

## What changed

- `Llm::SpeechToTextService` (new) — blob-in/text-out transcription
engine extracted from `Messages::AudioTranscriptionService`: size limit,
temp-file download, model resolution via `Llm::FeatureRouter`, the
OpenAI call, and Captain credit accounting. `.available_for?` holds the
shared gate.
- `Messages::AudioTranscriptionService` — now a thin wrapper over that
engine; its public contract is unchanged, so
`Captain::OpenAiMessageBuilderService` is unaffected.
- `Voice::CallTranscriptionService` / `Voice::CallTranscriptionJob`
(new) — transcribe `call.recording` into `calls.transcript`, then
rebroadcast the message so clients pick it up over the wire.
- `Voice::Provider::Twilio::RecordingAttachmentService` — enqueues the
job after the recording is attached.

The API and frontend needed no changes: `calls.transcript` already
existed, `_call.json.jbuilder` already serialized it, and
`VoiceCall.vue` already fed it to the audio chip. Nothing had ever
written the column.

Also wires `instrument_audio_transcription`, which existed but was never
called, so both transcription paths now emit LLM spans.
2026-08-12 16:54:49 +05:30
Shivam Mishra
a24f5a3e7a fix: anchor contact phone number validation (#15415)
Contact phone numbers with stray text in front of them, like
`abc+12312312321`, were saving successfully instead of being rejected as
invalid. Agents could end up with unusable numbers on a contact, and the
same values were persisted rather than discarded when captured through
the live chat widget.

## How to reproduce

1. Open a contact and edit its details.
2. Set the phone number to `abc+12312312321` via the API (`PATCH
/api/v1/accounts/:id/contacts/:id`).
3. Before this change the update succeeds. Now it fails validation.

## What changed

The E.164 format check was missing a leading `\A` anchor, so Rails
matched it anywhere in the string and accepted any prefix ahead of a
valid number. Both the validation and the `phone_number_format` fallback
used by `discard_invalid_attrs` are now anchored, so the widget path
discards these values instead of storing them.

Contacts already holding a prefixed number will now fail validation on
their next save. Worth a count on production first:

```sql
SELECT count(*) FROM contacts WHERE phone_number !~ '^\+[1-9][0-9]{1,14}$' AND phone_number <> '';
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-08-12 15:28:49 +05:30
Muhsin Keloth
79405f76c4 feat(whatsapp): display click-to-chat ad referrals (#15424)
WhatsApp click-to-chat ad referrals are already stored on incoming
messages, but agents only see the customer’s text. This displays the
originating ad preview directly in the message bubble, including
available media, headline, body, and source link. Attribution
identifiers remain hidden.

### Things to know

- The card renders only when `content_attributes.referral` is present.
- Invalid or non-HTTP media and source URLs fall back safely.
- Existing messages without referral metadata are unchanged.

### How to test

1. Open a WhatsApp conversation containing an incoming message with
`content_attributes.referral`.
2. Confirm the ad preview appears above the customer text.
3. Confirm the source opens in a new tab and missing or invalid media
does not break the message bubble.


Fixes
https://linear.app/chatwoot/issue/CW-6206/add-whatsapp-ad-preview-support-in-chatwoot-inbox

---------

Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
2026-08-12 13:28:33 +05:30
Sivin Varghese
541f91acae fix: allow resizing the reply editor while a Copilot suggestion is active (#15391) 2026-08-12 12:42:31 +05:30
Sivin Varghese
5a02616189 fix: inline editor in the contact sidebar clips longer values (#15403) 2026-08-12 12:32:31 +05:30
Devi R
8397fa7eaf fix: include account_id in FCM push payload (#15260)
## Description

- fcm_push_data didn't include the account id, so mobile clients had no
way to know which account a push notification belonged to. This adds
account_id to the FCM payload (it was already present in push_event_data
for ActionCable, just not FCM).
- Prerequisite for the mobile-side fix for
[chatwoot-mobile-app#1121](https://github.com/chatwoot/chatwoot-mobile-app/pull/1121)
(opening a conversation from a notification for a non-active account).
- Added a spec asserting fcm_push_data includes the account id.

Fixes
[CW-4235](https://linear.app/chatwoot/issue/CW-4235/the-conversation-fails-to-open-when-the-notifications-account-differs)

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2026-08-11 20:10:51 -07:00