115 lines
6.4 KiB
Markdown
115 lines
6.4 KiB
Markdown
|
|
# CLAUDE.md
|
||
|
|
|
||
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
|
|
||
|
|
## Repository Overview
|
||
|
|
|
||
|
|
This is a monorepo for CDR Link - a Zammad addon and supporting services built by the Center for Digital Resilience. It adds Signal, WhatsApp, and voice channel support to Zammad via a custom `.zpm` addon package, along with a standalone WhatsApp bridge service. It uses pnpm workspaces and Turborepo for orchestration.
|
||
|
|
|
||
|
|
**Tech Stack:**
|
||
|
|
- Zammad 6.5.x as the core helpdesk platform
|
||
|
|
- Ruby (Rails initializers, controllers, models, jobs) for the Zammad addon
|
||
|
|
- TypeScript/Node.js for build tooling and the WhatsApp bridge
|
||
|
|
- CoffeeScript for Zammad legacy UI extensions
|
||
|
|
- Vue 3 for Zammad desktop UI extensions
|
||
|
|
- Docker for containerization
|
||
|
|
- PostgreSQL, Redis, Memcached as backing services
|
||
|
|
|
||
|
|
## Project Structure
|
||
|
|
|
||
|
|
```
|
||
|
|
apps/
|
||
|
|
bridge-whatsapp/ # Standalone WhatsApp bridge (Hapi.js + Baileys)
|
||
|
|
packages/
|
||
|
|
zammad-addon-link/ # Zammad addon source (Ruby, CoffeeScript, Vue, TS)
|
||
|
|
src/ # Addon source files (installed into /opt/zammad/)
|
||
|
|
scripts/build.ts # Builds .zpm package from src/
|
||
|
|
scripts/migrate.ts # Generates new migration stubs
|
||
|
|
docker/
|
||
|
|
zammad/ # Custom Zammad Docker image
|
||
|
|
Dockerfile # Extends zammad/zammad-docker-compose base image
|
||
|
|
install.rb # Extracts addon files from .zpm at build time
|
||
|
|
setup.rb # Registers addon packages at container startup
|
||
|
|
addons/ # Built .zpm files (gitignored, generated by turbo build)
|
||
|
|
compose/ # Docker Compose service definitions
|
||
|
|
```
|
||
|
|
|
||
|
|
## Common Development Commands
|
||
|
|
|
||
|
|
```bash
|
||
|
|
pnpm install # Install all dependencies
|
||
|
|
turbo build # Build all packages (generates .zpm files)
|
||
|
|
npm run docker:zammad:build # Build custom Zammad Docker image
|
||
|
|
npm run docker:all:up # Start all Docker services
|
||
|
|
npm run docker:all:down # Stop all Docker services
|
||
|
|
npm run docker:zammad:restart # Restart railsserver + scheduler (after Ruby changes)
|
||
|
|
npm run update-version <version> # Update version across all packages
|
||
|
|
npm run clean # Remove all build artifacts and dependencies
|
||
|
|
```
|
||
|
|
|
||
|
|
## Zammad Addon Architecture
|
||
|
|
|
||
|
|
### Addon Build & Deploy Pipeline
|
||
|
|
|
||
|
|
1. `turbo build` runs `tsx scripts/build.ts` in `packages/zammad-addon-link/`
|
||
|
|
2. Build script base64-encodes all files under `src/`, produces `docker/zammad/addons/zammad-addon-link-v{version}.zpm`
|
||
|
|
3. `docker/zammad/Dockerfile` builds a custom image:
|
||
|
|
- Copies `.zpm` files and runs `install.rb` to extract addon files into the Zammad directory tree
|
||
|
|
- Rebuilds Vite frontend (`bundle exec vite build`) to include addon Vue components
|
||
|
|
- Precompiles assets (`rake assets:precompile`) to include addon CoffeeScript
|
||
|
|
- Applies `sed` patches (OpenSearch compatibility, entrypoint injection)
|
||
|
|
4. At container startup, `setup.rb` registers the addon via `Package.install()` and runs migrations
|
||
|
|
|
||
|
|
### How the Addon Extends Zammad
|
||
|
|
|
||
|
|
**New files (no upstream conflict risk):** Controllers, channel drivers, jobs, routes, policies, library classes, views, CSS, SVG icons, frontend plugins. These add Signal/WhatsApp/voice channel support.
|
||
|
|
|
||
|
|
**Replaced stock files (HIGH conflict risk - must be manually merged on Zammad upgrades):**
|
||
|
|
- `app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/ArticleReply.vue` - Adds channel whitelist filtering via `cdr_link_allowed_channels` setting
|
||
|
|
- `app/frontend/apps/desktop/pages/personal-setting/views/PersonalSettingNotifications.vue` - Adds Signal notification recipient field
|
||
|
|
- `app/frontend/apps/desktop/components/Form/fields/FieldNotifications/FieldNotificationsInput.vue` - Adds Signal column to notification matrix
|
||
|
|
- `app/frontend/apps/desktop/components/Form/fields/FieldNotifications/types.ts` - Extended notification types
|
||
|
|
- `app/assets/javascripts/app/controllers/_profile/notification.coffee` - Signal notification prefs (legacy UI)
|
||
|
|
- `app/assets/javascripts/app/controllers/_ui_element/notification_matrix.coffee` - Signal column (legacy UI)
|
||
|
|
- `app/assets/javascripts/app/lib/mixins/ticket_notification_matrix.coffee` - Notification matrix mixin
|
||
|
|
- `app/assets/javascripts/app/views/generic/notification_matrix.jst.eco` - Notification matrix template
|
||
|
|
- `app/assets/javascripts/app/views/profile/notification.jst.eco` - Notification profile template
|
||
|
|
|
||
|
|
**Runtime monkey-patches (HIGH conflict risk):**
|
||
|
|
- `config/initializers/opensearch_compatibility.rb` - Prepends to `SearchIndexBackend._mapping_item_type_es()` to replace `'flattened'` with `'flat_object'` for OpenSearch
|
||
|
|
- `config/initializers/cdr_signal.rb` - Injects `after_create` callbacks into `Ticket::Article` and `Link` models
|
||
|
|
- `config/initializers/cdr_whatsapp.rb` - Injects `after_create` callback into `Ticket::Article`
|
||
|
|
|
||
|
|
**Dockerfile-level patches:**
|
||
|
|
- `lib/search_index_backend.rb` - `sed` replaces `'flattened'` with `'flat_object'`
|
||
|
|
- `/docker-entrypoint.sh` - `sed` injects addon install commands after `# es config` anchor
|
||
|
|
- `contrib/nginx/zammad.conf` - Adds `/link` proxy location in embedded mode
|
||
|
|
|
||
|
|
### Key Zammad API Dependencies
|
||
|
|
|
||
|
|
The addon depends on these Zammad interfaces remaining stable:
|
||
|
|
- `Channel::Driver` interface (`fetchable?`, `disconnect`, `deliver`, `streamable?`)
|
||
|
|
- `Ticket::Article` model callbacks and `Sender`/`Type` lookup by name
|
||
|
|
- `Link` model and `Link::Type`/`Link::Object`
|
||
|
|
- `SearchIndexBackend._mapping_item_type_es` method
|
||
|
|
- `Transaction` backend registration system
|
||
|
|
- `Package.install(file:)` / `Package.uninstall(name:, version:)` API
|
||
|
|
- `CreatesTicketArticles` controller concern
|
||
|
|
- Policy naming convention (`controllers/<name>_controller_policy.rb`)
|
||
|
|
|
||
|
|
## Zammad Development Notes
|
||
|
|
|
||
|
|
- After changing any Ruby files, restart railsserver and scheduler: `npm run docker:zammad:restart`
|
||
|
|
- The addon must be rebuilt (`turbo build`) and the Docker image rebuilt (`npm run docker:zammad:build`) for changes to take effect in Docker
|
||
|
|
- Use `/zammad-compat <version>` to check upstream Zammad for breaking changes before upgrading
|
||
|
|
- The current Zammad base version is set in `docker/zammad/Dockerfile` as `ARG ZAMMAD_VERSION`
|
||
|
|
|
||
|
|
## Docker Services
|
||
|
|
|
||
|
|
Defined in `docker/compose/`:
|
||
|
|
- **zammad.yml**: zammad-init, zammad-railsserver, zammad-nginx, zammad-scheduler, zammad-websocket, zammad-memcached, zammad-redis
|
||
|
|
- **bridge-whatsapp.yml**: bridge-whatsapp
|
||
|
|
- **postgresql.yml**: postgresql
|
||
|
|
- **signal-cli-rest-api.yml**: signal-cli-rest-api
|
||
|
|
- **opensearch.yml**: opensearch + dashboards
|