chore(overlay): scaffold custom/ overlay tree and add microsoft_shared? predicate
Foundation for LeadChat customizations using Chatwoot's built-in custom/ extension mechanism (ChatwootApp.extensions). Adds: - LEADCHAT.md: index of every customization touchpoint, updated as work lands - custom/: overlay tree where Custom::Leadchat::* modules live, autoloaded alongside enterprise/ via a parallel block in config/application.rb - Channel::Email#microsoft_shared? predicate as the first overlay (used by the upcoming Microsoft 365 Shared Inbox provider) OSS-file additions wrapped in '# === LeadChat: ===' markers so future upstream-merge conflicts are mechanical.
This commit is contained in:
49
LEADCHAT.md
Normal file
49
LEADCHAT.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# LeadChat customizations
|
||||
|
||||
This file is the index of every LeadChat-specific customization on top of upstream Chatwoot. Consult it during upstream merges to know what's customized and where conflicts may surface.
|
||||
|
||||
LeadChat is a white-label Chatwoot fork maintained on the `leadchat` branch. Customizations are layered using Chatwoot's built-in `custom/` extension mechanism (see [`lib/chatwoot_app.rb`](lib/chatwoot_app.rb) — `ChatwootApp.extensions` includes `'custom'` automatically when a `custom/` directory exists at repo root).
|
||||
|
||||
## Layering strategy
|
||||
|
||||
1. **Overlay modules under `custom/`** — preferred for Ruby modifications. New code lives in `custom/app/...` under the `Custom::Leadchat::*` namespace; OSS files only get a one-line `include_mod_with` / `prepend_mod_with` hook that Chatwoot's extension loader resolves automatically.
|
||||
2. **Direct edits to OSS** — only where no overlay mechanism exists (routes, schedule, Vue components). Each block is wrapped in `# === LeadChat: <feature> (start/end) ===` markers so future merge conflicts are mechanical.
|
||||
3. **Brand script** — separate process that overwrites brand strings in upstream files even after they're updated. Listed in "Brand script targets" below so we can extend its rules as new strings surface.
|
||||
|
||||
## Customization categories
|
||||
|
||||
### A. Overlay modules (Custom::Leadchat::*)
|
||||
|
||||
| Hook in OSS file | Overlay file | Adds |
|
||||
|---|---|---|
|
||||
| `app/models/channel/email.rb` (bottom) | `custom/app/models/custom/leadchat/channel/email_extension.rb` | `Channel::Email#microsoft_shared?` predicate |
|
||||
|
||||
### B. Direct edits to OSS files
|
||||
|
||||
| File | Change | Marker |
|
||||
|---|---|---|
|
||||
| `config/application.rb` | Mirror enterprise/ autoload setup for `custom/` so `Custom::*` modules are autoloaded and `custom/config/initializers/**/*.rb` are required | `# === LeadChat: custom/ overlay autoload ===` |
|
||||
| `app/models/channel/email.rb` (bottom) | One-line `include_mod_with` hook for the email_extension overlay | `# === LeadChat: microsoft_shared ===` |
|
||||
|
||||
### C. New top-level files (no upstream conflict potential)
|
||||
|
||||
| Path | Purpose |
|
||||
|---|---|
|
||||
| `LEADCHAT.md` | This file |
|
||||
| `custom/` | Root of LeadChat overlay tree, picked up by `ChatwootApp.custom?` and the Phase-0 autoload setup |
|
||||
|
||||
### D. Brand script targets
|
||||
|
||||
Strings/files that the brand script rewrites away from "Chatwoot". Extend this list whenever a new "Chatwoot" mention surfaces in product UI.
|
||||
|
||||
- `app/javascript/dashboard/routes/dashboard/settings/inbox/components/SenderNameExamplePreview.vue` lines 33, 43 — hardcoded `businessName: 'Chatwoot'` in sender-name preview tiles. (Discovered 2026-04-27 while building the Microsoft Shared Inbox feature; not yet handled by the brand script.)
|
||||
|
||||
## Active feature work
|
||||
|
||||
- **Microsoft Shared Inbox provider** (in progress) — new `microsoft_shared` Email Channel type backed entirely by Microsoft Graph API, supports multiple shared mailboxes per OAuth via separate channel-add flows, bypasses Security Defaults / SMTP AUTH retirement. Plan: `~/.claude/plans/starry-mapping-snowflake.md`.
|
||||
|
||||
## Conventions
|
||||
|
||||
- Conventional Commits (`type(scope): subject`)
|
||||
- No Claude attribution in commits or PR bodies
|
||||
- Update this file as each customization lands, not as a final pass
|
||||
@@ -78,3 +78,7 @@ class Channel::Email < ApplicationRecord
|
||||
self.forward_to_email ||= "#{SecureRandom.hex}@#{account.inbound_email_domain}"
|
||||
end
|
||||
end
|
||||
|
||||
# === LeadChat: microsoft_shared (start) ===
|
||||
Channel::Email.include_mod_with('Leadchat::Channel::EmailExtension')
|
||||
# === LeadChat: microsoft_shared (end) ===
|
||||
|
||||
@@ -51,6 +51,21 @@ module Chatwoot
|
||||
enterprise_initializers = Rails.root.join('enterprise/config/initializers')
|
||||
Dir[enterprise_initializers.join('**/*.rb')].each { |f| require f } if enterprise_initializers.exist?
|
||||
|
||||
# === LeadChat: custom/ overlay autoload (start) ===
|
||||
# Mirrors the enterprise/ setup so Custom::* modules under custom/app/ are autoloaded
|
||||
# and registered with ChatwootApp.extensions (lib/chatwoot_app.rb#custom?).
|
||||
if Rails.root.join('custom').exist?
|
||||
config.eager_load_paths << Rails.root.join('custom/lib') if Rails.root.join('custom/lib').exist?
|
||||
# rubocop:disable Rails/FilePath
|
||||
config.eager_load_paths += Dir["#{Rails.root}/custom/app/**"]
|
||||
# rubocop:enable Rails/FilePath
|
||||
config.paths['app/views'].unshift('custom/app/views') if Rails.root.join('custom/app/views').exist?
|
||||
|
||||
custom_initializers = Rails.root.join('custom/config/initializers')
|
||||
Dir[custom_initializers.join('**/*.rb')].each { |f| require f } if custom_initializers.exist?
|
||||
end
|
||||
# === LeadChat: custom/ overlay autoload (end) ===
|
||||
|
||||
# Settings in config/environments/* take precedence over those specified here.
|
||||
# Application configuration can go into files in config/initializers
|
||||
# -- all .rb files in that directory are automatically loaded after loading
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
module Custom::Leadchat::Channel::EmailExtension
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def microsoft_shared?
|
||||
provider == 'microsoft_shared'
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user