chatwoot/spec
Shivam Mishra 3d20a7b049
feat: generate Help Center for Onboarding (#14370)
## Manually triggering help center generation

Open a Rails console (`bundle exec rails console`):

```ruby
account = Account.find(<ACCOUNT_ID>)
user    = account.users.first

# Optional: refresh brand info from the customer's website
domain = 'example.com'
result = WebsiteBrandingService.new("noreply@#{domain}").perform
account.update!(
  name: result[:title].presence || account.name,
  custom_attributes: account.custom_attributes.merge('website' => domain, 'brand_info' => result)
)

# Optional: wipe existing portals so a fresh one is created
account.portals.destroy_all

Onboarding::HelpCenterCreationService.new(account, user).perform
```

Sidekiq must be running — articles are written by
`Onboarding::HelpCenterArticleGenerationJob`. Avoid running on
production; generation calls the LLM provider.


### Generation flow (Happy Path) 

```mermaid
sequenceDiagram
    autonumber

    participant Kickoff as HelpCenterCreationService
    participant DB as DB
    participant GenJob as HelpCenterArticleGenerationJob
    participant Curator as HelpCenterCurator
    participant Firecrawl as Firecrawl
    participant CuratorLLM as Curation LLM
    participant Redis as Redis Progress
    participant WriterJob as HelpCenterArticleWriterJob
    participant Builder as HelpCenterArticleBuilder
    participant WriterLLM as Writer LLM
    participant Cable as ActionCable

    Kickoff->>DB: Create portal for account<br/>homepage_link=https://chatwoot.com
    Kickoff->>DB: Attach brand logo if available
    Kickoff->>GenJob: Enqueue generation job<br/>account_id, portal_id, user_id, generation_id

    GenJob->>Curator: Curate help center plan
    Curator->>Firecrawl: map https://chatwoot.com<br/>search: docs help support faq
    Firecrawl-->>Curator: Return discovered links
    Curator->>CuratorLLM: Select categories + article plans<br/>from discovered links only
    CuratorLLM-->>Curator: Return categories, articles, allowed_urls

    GenJob->>DB: Create portal categories
    GenJob->>GenJob: Stamp articles with category_id
    GenJob->>GenJob: Filter article URLs against allowed_urls
    GenJob->>GenJob: Drop articles with no category<br/>or no approved source URLs

    GenJob->>Redis: Start progress<br/>status=generating, total=N, finished=0

    loop For each approved article
      GenJob->>WriterJob: Enqueue writer job<br/>title, category_id, approved URLs
    end

    par Writer jobs run independently
      WriterJob->>Builder: Build article from approved URLs
      Builder->>Firecrawl: batch_scrape approved URLs
      Firecrawl-->>Builder: Return Markdown source pages
      Builder->>WriterLLM: Rewrite sources into one article
      WriterLLM-->>Builder: Return title, description, Markdown content
      Builder->>DB: Create draft portal article<br/>meta.source_urls
      WriterJob->>Redis: Increment finished count
      WriterJob->>Cable: Broadcast help_center.article_generated
    end

    WriterJob->>Redis: If finished >= total<br/>mark status=completed
    WriterJob->>Cable: Broadcast help_center.generation_completed
```

### Redis State Management

```mermaid
 stateDiagram-v2
    [*] --> active_pointer_set
    active_pointer_set --> generating: generation job creates valid plan
    active_pointer_set --> skipped: curation skipped/failed

    generating --> generating: each writer job increments finished
    generating --> completed: finished == total
    generating --> ignored_completion: generation_id superseded

    skipped --> [*]
    completed --> [*]
    ignored_completion --> [*]
```
2026-05-21 16:25:01 +05:30
..
actions fix: Skip redundant contact saves in ContactIdentifyAction (#13778) 2026-03-11 21:40:38 -07:00
assets fix: standardize contact company field on company_name (#14099) 2026-04-27 18:43:26 +05:30
builders feat: enable quoted reply for everyone (#14469) 2026-05-15 10:59:48 -07:00
channels fix: Move contact events to account stream rather than individual user stream (#11082) 2025-03-13 17:46:48 -07:00
config feat: add GuideJar embed support in HC (#13944) 2026-03-30 14:19:02 +05:30
configs chore: Enable the new Rubocop rules (#7122) 2023-05-19 14:37:10 +05:30
controllers feat: Unread Count: added api, store refresher, invalidation and events (2/3)[CW-6851] (#14369) 2026-05-20 17:36:09 +05:30
dispatchers Non blocking event dispatch (#652) 2020-03-29 19:18:30 +05:30
drops feat: Add the support for custom attributes in message variables (#8511) 2023-12-08 14:13:35 -08:00
enterprise feat: generate Help Center for Onboarding (#14370) 2026-05-21 16:25:01 +05:30
factories feat: Ability to specify the authentication type for imap server (#12306) 2026-05-08 16:40:15 +05:30
finders feat(rollup): report builder abstraction [2/3] (#13798) 2026-04-20 11:15:48 +05:30
fixtures fix(mailbox): render inline images without Content-Disposition (#11949) 2026-05-06 18:56:31 +05:30
helpers chore: Refactor UTM params to stay compliant with standards (#12312) 2025-08-29 11:46:52 -07:00
integration Fix url in emails, add frontendURL helper (#19) 2019-08-25 19:59:28 +05:30
jobs fix: atomically claim conversation to prevent duplicate assignment (#14495) 2026-05-21 16:14:28 +05:30
lib feat: base layer for unread counts (store, counter and builder) (1/3)[CW-6851] (#14368) 2026-05-20 14:26:21 +05:30
listeners feat: Unread Count: added api, store refresher, invalidation and events (2/3)[CW-6851] (#14369) 2026-05-20 17:36:09 +05:30
mailboxes fix(mailbox): render inline images without Content-Disposition (#11949) 2026-05-06 18:56:31 +05:30
mailers fix: validate OpenAI hook credentials (#14068) 2026-05-18 14:08:57 +05:30
models feat: Unread Count: added api, store refresher, invalidation and events (2/3)[CW-6851] (#14369) 2026-05-20 17:36:09 +05:30
policies chore: Enforce custom role permissions on conversation access (#12583) 2025-10-22 20:23:37 -07:00
presenters fix: index email subject from conversation for outbound messages (#14122) 2026-04-22 20:36:35 +05:30
requests/api/v1 feat: allow disabling 2FA with a backup code (#14102) 2026-04-28 10:09:41 +07:00
services feat: Unread Count: Frontend changes for showing unread count badges (3/3)[CW-6851] (#14372) 2026-05-20 19:21:25 +05:30
support feat: base layer for unread counts (store, counter and builder) (1/3)[CW-6851] (#14368) 2026-05-20 14:26:21 +05:30
swagger feat: validate OpenAPI spec using Skooma (#13623) 2026-03-10 18:33:55 -07:00
coverage_helper.rb ci(circleci): switch coverage reporting to Qlty orb (#12337) 2025-08-31 00:39:34 +05:30
rails_helper.rb feat: base layer for unread counts (store, counter and builder) (1/3)[CW-6851] (#14368) 2026-05-20 14:26:21 +05:30
spec_helper.rb ci(circleci): switch coverage reporting to Qlty orb (#12337) 2025-08-31 00:39:34 +05:30
test_helper.rb ci(circleci): switch coverage reporting to Qlty orb (#12337) 2025-08-31 00:39:34 +05:30