6.4 KiB
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
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
turbo buildrunstsx scripts/build.tsinpackages/zammad-addon-link/- Build script base64-encodes all files under
src/, producesdocker/zammad/addons/zammad-addon-link-v{version}.zpm docker/zammad/Dockerfilebuilds a custom image:- Copies
.zpmfiles and runsinstall.rbto 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
sedpatches (OpenSearch compatibility, entrypoint injection)
- Copies
- At container startup,
setup.rbregisters the addon viaPackage.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 viacdr_link_allowed_channelssettingapp/frontend/apps/desktop/pages/personal-setting/views/PersonalSettingNotifications.vue- Adds Signal notification recipient fieldapp/frontend/apps/desktop/components/Form/fields/FieldNotifications/FieldNotificationsInput.vue- Adds Signal column to notification matrixapp/frontend/apps/desktop/components/Form/fields/FieldNotifications/types.ts- Extended notification typesapp/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 mixinapp/assets/javascripts/app/views/generic/notification_matrix.jst.eco- Notification matrix templateapp/assets/javascripts/app/views/profile/notification.jst.eco- Notification profile template
Runtime monkey-patches (HIGH conflict risk):
config/initializers/opensearch_compatibility.rb- Prepends toSearchIndexBackend._mapping_item_type_es()to replace'flattened'with'flat_object'for OpenSearchconfig/initializers/cdr_signal.rb- Injectsafter_createcallbacks intoTicket::ArticleandLinkmodelsconfig/initializers/cdr_whatsapp.rb- Injectsafter_createcallback intoTicket::Article
Dockerfile-level patches:
lib/search_index_backend.rb-sedreplaces'flattened'with'flat_object'/docker-entrypoint.sh-sedinjects addon install commands after# es configanchorcontrib/nginx/zammad.conf- Adds/linkproxy location in embedded mode
Key Zammad API Dependencies
The addon depends on these Zammad interfaces remaining stable:
Channel::Driverinterface (fetchable?,disconnect,deliver,streamable?)Ticket::Articlemodel callbacks andSender/Typelookup by nameLinkmodel andLink::Type/Link::ObjectSearchIndexBackend._mapping_item_type_esmethodTransactionbackend registration systemPackage.install(file:)/Package.uninstall(name:, version:)APICreatesTicketArticlescontroller 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/DockerfileasARG 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