Mirror importado do GitHub: https://github.com/Rodribm10/iachat
Go to file
Cayo P. R. Oliveira c6bfd1eed3
feat: schedule messages recurrence (#240)
* feat(scheduled-messages): add recurring scheduled messages

Implements the recurring scheduled messages feature allowing agents to
configure recurrence rules when scheduling messages, with automatic
creation of subsequent scheduled messages after each send.

Backend:
- RecurringScheduledMessage model with JSONB recurrence_rule validation
- RecurrenceCalculatorService for next occurrence date calculation
- RecurrenceDescriptionService for human-readable rule descriptions
- CreateNextOccurrenceService for auto-creating child ScheduledMessages
- RecurringScheduledMessagesController with CRUD operations
- RecurringScheduledMessagePolicy for authorization
- Modified SendScheduledMessageJob to handle recurrence after send
- Updated due_for_sending scope to exclude resolved conversations
- ActionCable events for real-time updates
- Activity message i18n (en + pt-BR)

Frontend:
- RecurrenceDropdown.vue with contextual shortcut options
- RecurrenceCustomModal.vue for custom recurrence configuration
- RecurringScheduledMessageItem.vue for sidebar display
- Integration into ScheduledMessageModal.vue
- Updated ScheduledMessages.vue with recurrence section and filtering
- Vuex store module for recurring scheduled messages
- API client for CRUD operations
- WebSocket handlers in actionCable.js
- recurrenceHelpers.js utility functions
- i18n keys for en and pt-BR

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): fix creation and edit visibility

- Fix API payload key mismatch (snake_case vs camelCase) in modal submit
- Add status: 'active' to recurring creation payload
- Fix strong params to permit recurrence_rule array fields (week_days)
- Cast string values from strong params to integers for JSONB validation
- Show RecurrenceDropdown when editing (remove isEditing gate)
- Populate recurrenceRule from scheduled message's recurring parent
- Include recurring_scheduled_message_id and recurrence_rule in
  scheduled message jbuilder response

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): fix dropdown toggle and locale tag errors

- Use DropdownItem :click prop instead of @click to use the injected
  closeMenu from DropdownContainer context (default slot doesn't
  expose toggle)
- Normalize locale from pt_BR to pt-BR for Intl.DateTimeFormat
  compatibility in RecurringScheduledMessageItem

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(recurring-messages): add separator line and expandable history

- Add border separator between recurring messages section and
  pending/draft messages, matching the history section separator
- Replace static 'N enviadas' counter with clickable toggle that
  expands to show individual sent/failed child messages with
  status badges and formatted timestamps

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(recurring-messages): add click-to-navigate on sent children

Make sent child messages in recurring message history clickable.
Clicking navigates to the actual message in the conversation using
the messageId query param, same pattern as ScheduledMessageItem.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(recurring-messages): allow editing recurring messages

- Add edit button to RecurringScheduledMessageItem (active only)
- Transform recurring message into scheduledMessage-compatible shape
  with recurring_scheduled_message_id set, so the modal reuses
  the existing update path
- Handle edge case of removing recurrence from a recurring message
  (cancels series without trying to update a non-existent standalone)
- Sent history is preserved by the backend update action

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): show recurrence field without date selection

Remove v-if="scheduledDate" gate so the recurrence dropdown is
always visible in the modal. Falls back to today's date for
contextual shortcut labels when no date is selected yet.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): ensure recurrence visible on edit and add pending_scheduled_message to API

- Add pending_scheduled_message to recurring_scheduled_message jbuilder
  so REST API data matches WebSocket push_event_data
- Add fallback in openEditRecurringModal to find pending child from
  scheduled_messages array when pending_scheduled_message is absent
- Add same fallback in nextSendLabel computed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(scheduled-messages): add sections for Drafts and Pending messages in the UI

* refactor(scheduled-messages): merge RecurringScheduledMessageItem into ScheduledMessageItem

Consolidate the recurring message card into the existing
ScheduledMessageItem component instead of maintaining a separate
component. The unified component detects recurring messages via
recurrence_rule and conditionally shows:
- Recurrence description header with repeat icon
- Next send time label
- Expandable sent/failed children history with click-to-navigate
- Stop button (replaces delete) with confirmation modal
- Active/completed/cancelled status badges

Delete the now-unused RecurringScheduledMessageItem.vue.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(scheduled-messages): use blue badge for active, keep green for sent

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(scheduled-messages): remove draft and pending sections from UI and update recurrence title

* fix(recurring-messages): use Teleport for recurrence dropdown

Replace DropdownContainer with Teleport-based floating dropdown so
options render outside the modal. Fixes:
- Dropdown no longer enlarges the modal or causes scrolling
- Dropdown closes before Custom modal opens (no overlap)
- Auto-detects available space and opens above/below trigger

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): recalculate next date when recurrence rule changes

When editing a recurring message and changing the recurrence rule,
the pending occurrence date is now validated against the new rule.
If the user-provided date doesn't match (e.g. Thursday removed from
weekly days), the system computes the next valid date using
RecurrenceCalculatorService instead of blindly using the old date.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(scheduled-messages): resolve deprecated onClose and disabled type warnings

- Replace :on-close prop with @close event on woot-modal components
- Cast hasTemplate computed to boolean to fix disabled prop type check

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(scheduled-messages): replace remaining deprecated on-close props

- ScheduledMessages.vue delete confirm modal
- RecurrenceCustomModal.vue modal

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): address review feedback on PR #240

- Fix v-if/v-else bug hiding message list behind resolved warning
- Fix occurrences_sent incrementing on failed sends (skip_increment flag)
- Fix compute_next_valid_date using .min instead of .max
- Fix Vuex delete action to update state on cancel (not remove)
- Use atomic update_counters for occurrences_sent increment
- Add safe Date.iso8601 parsing with rescue in should_complete?
- Add null: false to occurrences_sent migration column
- Fix pt-BR accent: Recorrencia → Recorrências
- Use I18n.with_locale(account.locale) for all activity messages
- Fix N+1 in jbuilder partials (Ruby filtering + eager loading)
- Add interval >= 1 validation to RecurrenceCustomModal isValid
- Validate recurrence_rule presence when status is active
- Add ISO8601 date format validation for end_date
- Add unknown_agent i18n key for fallback

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): wrap create/update in transactions, clean pending on deactivation

- Wrap create and update flows in ActiveRecord transactions
- Move attachment purge after save! to prevent data loss on validation failure
- Destroy pending children when status transitions to non-active
- Fixes critical bug where stopping recurrence could leave armed pending messages

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): prevent monthly/yearly day-of-month drift

Store the original intended day in recurrence_rule JSONB as month_day
(for monthly) and year_day/year_month (for yearly). The calculator
now uses these stored values instead of @last_date.day, preventing
drift after short months cap the day (e.g., Jan 31 → Feb 28 → all
subsequent months stuck on 28).

Backend:
- RecurrenceCalculatorService: use rule[:month_day] for monthly and
  rule[:year_day]/rule[:year_month] for yearly calculations
- Controller: permit and cast the new integer keys

Frontend:
- recurrenceHelpers: yearly shortcuts include year_day/year_month
- RecurrenceCustomModal: emit month_day for monthly day_of_month
  rules and year_day/year_month for yearly rules

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): i18n description services, align due_for_sending scope

Backend:
- RecurrenceDescriptionService: replace hardcoded English with I18n.t()
  calls; accept locale parameter and use I18n.with_locale
- RecurringScheduledMessage model: pass account locale to description service
- ScheduledMessage: align due_for_sending? instance method with scope by
  checking conversation status (open/pending)

Frontend:
- buildRecurrenceDescription: use t() i18n function instead of manual
  isPt locale branching
- Add DESCRIPTION i18n keys to en/conversation.json and pt_BR/conversation.json
- Update RecurrenceDropdown and ScheduledMessageItem callers to pass t

i18n:
- Add recurring_scheduled_messages.description.* keys to en.yml and pt_BR.yml

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): keep pending child when deactivating recurrence

When editing a recurring message to disable recurrence while setting a
future send date, the pending child message is now preserved instead of
being destroyed. This allows a 'final send' without creating new
recurrences (the send job already guards with recurring&.active?).

Backend:
- Add update_pending_on_deactivation: updates pending child's
  scheduled_at or creates a final pending occurrence
- Replace destroy_all in update's non-active branch

Frontend:
- activeRecurringMessages now includes non-active recurring messages
  that still have a pending child (pending_scheduled_message)
- Stop button hidden for already-cancelled recurring messages
- inactiveRecurringMessages excludes messages with pending children

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): prevent removing recurrence from existing recurring message

Once a scheduled message has recurrence, the 'Does not repeat' option is
hidden from the RecurrenceDropdown when editing. This avoids edge cases
where deactivating recurrence leaves the message in an ambiguous display
state.

- RecurrenceDropdown: add hideNoRepeat prop, filter NO_REPEAT from shortcuts
- ScheduledMessageModal: pass hideNoRepeat when isEditingRecurring
- Revert update_pending_on_deactivation (no longer reachable from UI)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): address CodeRabbit review feedback

- ScheduledMessage#push_event_data: expose recurring_scheduled_message_id
  in ActionCable payloads so frontend correctly classifies children
- RecurringScheduledMessagePolicy: add agent_bot? check for parity with
  ScheduledMessagePolicy
- RecurrenceCalculatorService: guard against nil/empty week_days
- Factory: bind inbox and account to conversation to prevent cross-account
  flakiness in specs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(recurring-messages): update schema to enforce non-null constraint on occurrences_sent

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: gabrieljablonski <contact@gabrieljablonski.com>
2026-03-19 22:51:14 -03:00
__mocks__ Feature: Agent Profile Update with avatar (#449) 2020-02-16 17:20:38 +05:30
.circleci fix: Fixes reply-to in WhatsApp Cloud API (#13467) 2026-02-06 14:01:01 -08:00
.claude feat: group conversations (#228) 2026-03-19 21:56:58 -03:00
.dependabot Add Dependabot config (#217) 2019-11-25 09:48:11 +05:30
.devcontainer chore: upgrade node to v24.13 (#13291) 2026-01-15 20:28:13 -08:00
.github feat: edit contact modal confirm discard (#199) 2026-01-27 20:03:42 -03:00
.husky fix: Update pre-commit hook to handle staged deleted files (#11357) 2025-04-24 16:54:53 +05:30
.qlty feat: Add Pinia support and relocate store factory (#12854) 2025-11-28 16:31:59 +05:30
.vscode chore: handle scss unknown at rule warnings 2025-04-03 23:28:38 -03:00
.windsurf/rules chore: Add development guidelines documentation for AI Agents (#11243) 2025-05-16 19:23:10 -07:00
app feat: schedule messages recurrence (#240) 2026-03-19 22:51:14 -03:00
bin chore: Update translations, add pnpm sync:i18n command (#10893) 2025-02-12 17:43:46 -08:00
clevercloud feat: Add support for Clever cloud deployments (#1703) 2021-01-29 17:08:40 +05:30
config feat: schedule messages recurrence (#240) 2026-03-19 22:51:14 -03:00
db feat: schedule messages recurrence (#240) 2026-03-19 22:51:14 -03:00
deployment Merge branch 'main' into chore/merge-upstream-4.10 2026-01-16 14:01:53 -03:00
docker feat: add audio transcoding support for WhatsApp Cloud API (#220) 2026-02-22 16:21:50 -03:00
enterprise feat: group conversations (#228) 2026-03-19 21:56:58 -03:00
lib feat: schedule messages recurrence (#240) 2026-03-19 22:51:14 -03:00
log Initial Commit 2019-08-14 15:18:44 +05:30
public chore: general improvements (#232) 2026-03-03 14:08:56 -03:00
rubocop fix: stream attachment handling in workers (#12870) 2025-12-05 13:02:53 -08:00
script chore: add script to throttle bulkreindex job creation and increase meta timeouts(#12626) 2025-10-13 16:21:45 +05:30
spec feat: schedule messages recurrence (#240) 2026-03-19 22:51:14 -03:00
swagger feat: group conversations (#228) 2026-03-19 21:56:58 -03:00
theme Merge branch 'main' into chore/merge-upstream-4.11.0 2026-02-17 23:05:26 -03:00
tmp Initial Commit 2019-08-14 15:18:44 +05:30
vendor feat: Sentiment model download and upload to vendor (#7526) 2023-07-18 12:17:50 +05:30
.all-contributorsrc [docs] Move contributors section to docs (#120) 2019-10-06 09:23:24 +05:30
.annotaterb.yml fix: annotaterb (#173) 2025-12-30 15:18:43 -03:00
.browserslistrc Initial Commit 2019-08-14 15:18:44 +05:30
.bundler-audit.yml chore: mitigate CVE-2021-41098 (#3101) 2021-09-28 19:34:11 +05:30
.dockerignore chore: add build id to settings page (#6873) 2023-04-18 00:35:35 +05:30
.editorconfig fix: Update .editorconfig to fix spaces and indent_style (#5612) 2022-10-12 14:00:42 -07:00
.env.example feat: group conversations (#228) 2026-03-19 21:56:58 -03:00
.eslintrc.js chore: Add "Coming Soon" overlay to voice channel selector (#11835) 2025-06-30 14:30:09 +05:30
.gitignore chore(dev): document codex worktree local setup (#13494) 2026-02-09 20:56:40 -08:00
.nvmrc chore: upgrade node to v24.13 (#13291) 2026-01-15 20:28:13 -08:00
.prettierrc chore: Execute campaigns based on matching URL (#2254) 2021-05-17 21:38:35 +05:30
.rspec Fix url in emails, add frontendURL helper (#19) 2019-08-25 19:59:28 +05:30
.rubocop.yml Revert "chore: Upgrade Rails to 7.2.2 and update Gemfile dependencies (#11037)" 2026-02-03 21:09:42 -08:00
.ruby-version chore: upgrade ruby version to 3.4.4 (#11524) 2025-05-21 19:40:07 +05:30
.scss-lint.yml feat(apps): Shopify Integration (#11101) 2025-03-19 15:37:55 -07:00
.slugignore chore: Upgrade to Rails 7 (#6719) 2023-05-06 10:44:52 +05:30
AGENTS.md fix: apply installation branding replacement in tooltip copy (#13538) 2026-02-13 16:47:25 -08:00
app.json Chore/merge upstream 4.8.0 (#150) 2025-11-19 16:25:58 -03:00
Capfile 🚨Fix Rubocop lint errors 2019-10-20 14:17:26 +05:30
CLAUDE.md chore: Add development guidelines documentation for AI Agents (#11243) 2025-05-16 19:23:10 -07:00
CODE_OF_CONDUCT.md General updates and add CODEOWNERS (#3685) 2022-01-05 12:37:22 +05:30
config.ru Initial Commit 2019-08-14 15:18:44 +05:30
CONTRIBUTING.md General updates and add CODEOWNERS (#3685) 2022-01-05 12:37:22 +05:30
crowdin.yml chore: Update Crowdin Config (#7375) 2023-06-23 23:02:55 +05:30
CUSTOM_BRANDING.md feat: custom branding (#68) 2025-06-12 22:11:19 -03:00
docker-compose.coolify.yaml chore: update docker-compose.coolify.yaml 2025-10-27 18:37:28 -03:00
docker-compose.production.yaml fix: add named volumes for storage, postgres, and redis (#11465) 2025-05-12 17:32:12 +05:30
docker-compose.test.yaml feat: switch to postgres docker images with pgvector support (v4.0) (#10658) 2025-01-14 19:45:42 +05:30
docker-compose.yaml feat: switch to postgres docker images with pgvector support (v4.0) (#10658) 2025-01-14 19:45:42 +05:30
Gemfile feat: add audio transcoding support for WhatsApp Cloud API (#220) 2026-02-22 16:21:50 -03:00
Gemfile.lock feat: add audio transcoding support for WhatsApp Cloud API (#220) 2026-02-22 16:21:50 -03:00
histoire.config.ts chore(dev): Update histoire config for deployment (#12374) 2025-09-11 13:05:54 +05:30
LICENSE chore: Update year in LICENSE (#8835) 2024-02-01 15:37:05 +05:30
Makefile chore: Improvements for codespace (#11667) 2025-06-04 00:21:23 -05:00
package.json feat: scheduled message shortcuts (#238) 2026-03-19 22:43:51 -03:00
pnpm-lock.yaml feat: scheduled message shortcuts (#238) 2026-03-19 22:43:51 -03:00
postcss.config.js feat: Vite + vue 3 💚 (#10047) 2024-10-02 00:36:30 -07:00
Procfile chore: add build id to settings page (#6873) 2023-04-18 00:35:35 +05:30
Procfile.dev feat: Vite + vue 3 💚 (#10047) 2024-10-02 00:36:30 -07:00
Procfile.test feat: Vite + vue 3 💚 (#10047) 2024-10-02 00:36:30 -07:00
Procfile.tunnel chore: Improvements for codespace (#11667) 2025-06-04 00:21:23 -05:00
Rakefile fix: Search rake task causing Rails boot error (#12416) 2025-09-15 22:21:59 +05:30
README.md chore: Update copyright year in README.md to 2026 (#13195) 2026-01-07 17:42:41 -08:00
SECURITY.md chore: Update SECURITY.md (#10705) 2025-01-16 10:59:33 -08:00
semantic.yml Chore: Update copy on Signup page (#1023) 2020-07-09 16:28:09 +05:30
tailwind.config.js chore: Update theme colors and add new Inter variable fonts (#13347) 2026-01-28 14:36:04 -08:00
VERSION_CW Bump version to 4.11.0 2026-02-17 15:35:20 -08:00
VERSION_CWCTL chore: upgrade node to 24.x LTS (#13004) 2026-01-12 18:10:23 +05:30
vite.config.ts feat: speed up circleci and github actions (#12849) 2025-11-19 15:32:48 +05:30
vitest.setup.js chore: Update buttons in dashboard (#11145) 2025-03-31 17:21:32 -07:00
workbox-config.js [Feature] Add PWA support (#157) 2019-10-18 12:37:09 +05:30

Header light mode Header dark mode

Chatwoot

The modern customer support platform, an open-source alternative to Intercom, Zendesk, Salesforce Service Cloud etc.

CircleCI Badge Docker Pull Badge Docker Build Badge Commits-per-month Discord uptime response time Artifact HUB

Deploy Deploy to DO

Chat dashboard dark mode Chat dashboard

Chatwoot is the modern, open-source, and self-hosted customer support platform designed to help businesses deliver exceptional customer support experience. Built for scale and flexibility, Chatwoot gives you full control over your customer data while providing powerful tools to manage conversations across channels.

Captain AI Agent for Support

Supercharge your support with Captain, Chatwoots AI agent. Captain helps automate responses, handle common queries, and reduce agent workload—ensuring customers get instant, accurate answers. With Captain, your team can focus on complex conversations while routine questions are resolved automatically. Read more about Captain here.

💬 Omnichannel Support Desk

Chatwoot centralizes all customer conversations into one powerful inbox, no matter where your customers reach out from. It supports live chat on your website, email, Facebook, Instagram, Twitter, WhatsApp, Telegram, Line, SMS etc.

📚 Help center portal

Publish help articles, FAQs, and guides through the built-in Help Center Portal. Enable customers to find answers on their own, reduce repetitive queries, and keep your support team focused on more complex issues.

🗂️ Other features

Collaboration & Productivity

  • Private Notes and @mentions for internal team discussions.
  • Labels to organize and categorize conversations.
  • Keyboard Shortcuts and a Command Bar for quick navigation.
  • Canned Responses to reply faster to frequently asked questions.
  • Auto-Assignment to route conversations based on agent availability.
  • Multi-lingual Support to serve customers in multiple languages.
  • Custom Views and Filters for better inbox organization.
  • Business Hours and Auto-Responders to manage response expectations.
  • Teams and Automation tools for scaling support workflows.
  • Agent Capacity Management to balance workload across the team.

Customer Data & Segmentation

  • Contact Management with profiles and interaction history.
  • Contact Segments and Notes for targeted communication.
  • Campaigns to proactively engage customers.
  • Custom Attributes for storing additional customer data.
  • Pre-Chat Forms to collect user information before starting conversations.

Integrations

  • Slack Integration to manage conversations directly from Slack.
  • Dialogflow Integration for chatbot automation.
  • Dashboard Apps to embed internal tools within Chatwoot.
  • Shopify Integration to view and manage customer orders right within Chatwoot.
  • Use Google Translate to translate messages from your customers in realtime.
  • Create and manage Linear tickets within Chatwoot.

Reports & Insights

  • Live View of ongoing conversations for real-time monitoring.
  • Conversation, Agent, Inbox, Label, and Team Reports for operational visibility.
  • CSAT Reports to measure customer satisfaction.
  • Downloadable Reports for offline analysis and reporting.

Documentation

Detailed documentation is available at chatwoot.com/help-center.

Translation process

The translation process for Chatwoot web and mobile app is managed at https://translate.chatwoot.com using Crowdin. Please read the translation guide for contributing to Chatwoot.

Branching model

We use the git-flow branching model. The base branch is develop. If you are looking for a stable version, please use the master or tags labelled as v1.x.x.

Deployment

Heroku one-click deploy

Deploying Chatwoot to Heroku is a breeze. It's as simple as clicking this button:

Deploy

Follow this link to understand setting the correct environment variables for the app to work with all the features. There might be breakages if you do not set the relevant environment variables.

DigitalOcean 1-Click Kubernetes deployment

Chatwoot now supports 1-Click deployment to DigitalOcean as a kubernetes app.

Deploy to DO

Other deployment options

For other supported options, checkout our deployment page.

Security

Looking to report a vulnerability? Please refer our SECURITY.md file.

Community

If you need help or just want to hang out, come, say hi on our Discord server.

Contributors

Thanks goes to all these wonderful people:

Chatwoot © 2017-2026, Chatwoot Inc - Released under the MIT License.