# 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 # 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/_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 ` 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