Add Claude .md and skill

This commit is contained in:
Darren Clarke 2026-02-13 18:34:13 +01:00
parent 1b5f85627c
commit 99b92fe4ce
3 changed files with 319 additions and 0 deletions

View file

@ -0,0 +1,197 @@
---
name: zammad-compat
description: Check upstream Zammad for breaking changes before upgrading the addon
disable-model-invocation: true
argument-hint: "[target-version]"
allowed-tools: Bash(git clone *), Bash(git -C /tmp/zammad-upstream *)
---
# Zammad Upstream Compatibility Check
Check the upstream zammad/zammad repository for changes that could break or require updates to our Zammad addon (`packages/zammad-addon-link`).
## Arguments
- `$ARGUMENTS` - Optional: target Zammad version/tag/branch to compare against (e.g. `6.6.0`, `stable`). If not provided, ask the user what version to compare against. The current version is in `docker/zammad/Dockerfile` as the `ZAMMAD_VERSION` ARG.
## Setup
1. Read the current Zammad version from `docker/zammad/Dockerfile` (the `ARG ZAMMAD_VERSION=` line).
2. Clone or update the upstream Zammad repository:
- If `/tmp/zammad-upstream` does not exist, clone it: `git clone --bare https://github.com/zammad/zammad.git /tmp/zammad-upstream`
- If it exists, update it: `git -C /tmp/zammad-upstream fetch --all --tags`
3. Determine the version range. The current version is the `ZAMMAD_VERSION` from step 1. The target version is the argument or user-provided version. Both versions should be used as git refs (tags are typically in the format `X.Y.Z`).
## Checks to Perform
Run ALL of these checks and compile results into a single report.
### 1. Replaced Stock Files
These are stock Zammad files that our addon REPLACES with modified copies. Changes upstream mean we need to port those changes into our modified versions.
For each file below, diff the upstream version between the current and target version. Report any changes found.
**Vue/TypeScript (Desktop UI):**
- `app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/ArticleReply.vue`
- `app/frontend/apps/desktop/pages/personal-setting/views/PersonalSettingNotifications.vue`
- `app/frontend/apps/desktop/components/Form/fields/FieldNotifications/FieldNotificationsInput.vue`
- `app/frontend/apps/desktop/components/Form/fields/FieldNotifications/types.ts`
**CoffeeScript (Legacy UI):**
- `app/assets/javascripts/app/controllers/_profile/notification.coffee`
- `app/assets/javascripts/app/controllers/_ui_element/notification_matrix.coffee`
- `app/assets/javascripts/app/lib/mixins/ticket_notification_matrix.coffee`
- `app/assets/javascripts/app/views/generic/notification_matrix.jst.eco`
- `app/assets/javascripts/app/views/profile/notification.jst.eco`
Command pattern for each file:
```bash
git -C /tmp/zammad-upstream diff <current-version> <target-version> -- <file-path>
```
If a file does not exist at either version, note that (it may have been added, removed, or renamed).
### 2. Monkey-Patched Files
These are files our addon patches at runtime via Ruby `prepend`, `include`, or `after_initialize` hooks. Changes to these files could break our patches.
**Search Backend (OpenSearch compatibility patch):**
- `lib/search_index_backend.rb` - We prepend `SearchIndexBackendOpenSearchPatch` to override `_mapping_item_type_es`. Check if this method signature or the `'flattened'` string usage has changed.
**Core Models (callback injection targets):**
- `app/models/ticket/article.rb` - We inject `after_create` callbacks via `include` for Signal and WhatsApp message delivery. Check for changes to the callback chain, model structure, or the `Sender`/`Type` lookup patterns.
- `app/models/link.rb` - We inject an `after_create` callback for Signal group setup on ticket split. Check for structural changes.
**Transaction System:**
- `app/models/transaction/` directory - We register `Transaction::SignalNotification` as backend `0105_signal_notification`. Check if the transaction backend system has been refactored.
**Icons:**
- `public/assets/images/icons.svg` - Our initializers append SVG icons at boot time. Check if the SVG structure or the icon injection mechanism has changed.
Command pattern:
```bash
git -C /tmp/zammad-upstream diff <current-version> <target-version> -- <file-path>
```
For the search backend specifically, also check if `_mapping_item_type_es` still exists and still returns `'flattened'`:
```bash
git -C /tmp/zammad-upstream show <target-version>:lib/search_index_backend.rb | grep -n -A5 '_mapping_item_type_es\|flattened'
```
### 3. API Surface Dependencies
These are Zammad APIs/interfaces/mixins our addon relies on. Changes could cause runtime failures.
**Channel Driver Interface:**
- `app/models/channel/driver/` - Check if the driver base class or interface expectations have changed (methods: `fetchable?`, `disconnect`, `deliver`, `streamable?`).
**Controller Concerns:**
- `app/controllers/concerns/creates_ticket_articles.rb` - Used by our webhook controllers. Check for interface changes.
**Ticket Article Types & Senders:**
- `app/models/ticket/article/type.rb` and `app/models/ticket/article/sender.rb` - We look up types by name (`'signal message'`, `'whatsapp message'`). Check for changes in how types are registered or looked up.
**Authentication/Authorization:**
- `app/policies/` directory structure - We create policies matching `controllers/` names. Check if the policy naming convention or base class has changed.
**Package System:**
- `lib/package.rb` or the package install/uninstall API - We use `Package.install(file:)` and `Package.uninstall(name:, version:)` in setup.rb.
**Scheduler/Job System:**
- `app/jobs/` base class patterns - Our jobs inherit from ApplicationJob. Check for changes.
Command pattern:
```bash
git -C /tmp/zammad-upstream diff --stat <current-version> <target-version> -- <path>
git -C /tmp/zammad-upstream diff <current-version> <target-version> -- <specific-file>
```
### 4. Path Collision Detection
Check if the target Zammad version has added any NEW files at paths that collide with our addon files. Our addon installs files at these paths:
**Controllers:** `app/controllers/channels_cdr_signal_controller.rb`, `channels_cdr_voice_controller.rb`, `channels_cdr_whatsapp_controller.rb`, `cdr_signal_channels_controller.rb`, `cdr_ticket_article_types_controller.rb`, `formstack_controller.rb`, `opensearch_controller.rb`
**Models:** `app/models/channel/driver/cdr_signal.rb`, `cdr_whatsapp.rb`, `app/models/ticket/article/enqueue_communicate_cdr_signal_job.rb`, `enqueue_communicate_cdr_whatsapp_job.rb`, `app/models/link/setup_split_signal_group.rb`, `app/models/transaction/signal_notification.rb`
**Jobs:** `app/jobs/communicate_cdr_signal_job.rb`, `communicate_cdr_whatsapp_job.rb`, `signal_notification_job.rb`, `create_ticket_from_form_job.rb`
**Libraries:** `lib/cdr_signal.rb`, `cdr_signal_api.rb`, `cdr_signal_poller.rb`, `cdr_whatsapp.rb`, `cdr_whatsapp_api.rb`, `signal_notification_sender.rb`
**Routes:** `config/routes/cdr_signal_channels.rb`, `channel_cdr_signal.rb`, `channel_cdr_voice.rb`, `channel_cdr_whatsapp.rb`, `cdr_ticket_article_types.rb`, `formstack.rb`, `opensearch.rb`
**Frontend Plugins:** `app/frontend/shared/entities/ticket-article/action/plugins/cdr_signal.ts`, `cdr_whatsapp.ts`, `app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/article-type/plugins/signalMessage.ts`, `whatsappMessage.ts`
Check if any of these paths exist in the target version:
```bash
for path in <list-of-paths>; do
git -C /tmp/zammad-upstream show <target-version>:$path 2>/dev/null && echo "COLLISION: $path exists upstream"
done
```
### 5. Dockerfile Patch Targets
Check files that are patched at Docker build time via `sed`:
- `lib/search_index_backend.rb` - `sed` replaces `'flattened'` with `'flat_object'`. Verify the string still exists in the target version.
- `contrib/nginx/zammad.conf` - Structure modified for embedded mode. Check for format changes.
- `docker-entrypoint.sh` - We inject addon install commands after the `# es config` comment. Verify this comment/anchor still exists.
Check the upstream Docker entrypoint:
```bash
git -C /tmp/zammad-upstream show <target-version>:contrib/docker/docker-entrypoint.sh 2>/dev/null | grep -n 'es config' || echo "Anchor comment not found - check entrypoint structure"
```
Also check the Zammad Docker Compose repo if relevant (the base image may come from `zammad/zammad-docker-compose`).
### 6. Database Schema Conflicts
Check if the target Zammad version adds any columns or tables that could conflict with our migrations:
- Column names: `whatsapp_uid`, `signal_uid`, `signal_username` on the users table
- Setting names containing: `signal_notification`, `cdr_link`, `formstack`, `opensearch_dashboard`
```bash
git -C /tmp/zammad-upstream diff <current-version> <target-version> -- db/migrate/ | grep -i 'signal\|whatsapp\|formstack\|opensearch'
```
### 7. Frontend Build System
Check if the Vite/asset pipeline configuration has changed significantly, since our addon relies on being compiled into the Zammad frontend:
```bash
git -C /tmp/zammad-upstream diff --stat <current-version> <target-version> -- vite.config.ts app/frontend/vite.config.ts config/initializers/assets.rb Gemfile
```
Also check if CoffeeScript/Sprockets support has been removed (would break our legacy UI files):
```bash
git -C /tmp/zammad-upstream show <target-version>:Gemfile 2>/dev/null | grep -i 'coffee\|sprockets'
```
## Report Format
Compile all findings into a structured report:
```
## Zammad Compatibility Report: <current-version> -> <target-version>
### CRITICAL (Action Required Before Upgrade)
- [List files that changed upstream AND are replaced by our addon - these need manual merging]
- [List any broken monkey-patch targets]
- [List any path collisions]
### WARNING (Review Needed)
- [List API surface changes that could affect our code]
- [List Dockerfile patch targets that changed]
- [List build system changes]
### INFO (No Action Needed)
- [List files checked with no changes]
- [List confirmed-safe paths]
### Recommended Actions
- For each CRITICAL item, describe what needs to be done
- Note any files that should be re-copied from upstream and re-patched
```
For each changed file in CRITICAL, show the upstream diff so the user can see what changed and decide how to integrate it.

8
.gitignore vendored
View file

@ -32,3 +32,11 @@ ENVIRONMENT_VARIABLES_MIGRATION.md
local-scripts/*
docs/
packages/zammad-addon-link/test/
# Allow Claude Code project config (overrides global gitignore)
!CLAUDE.md
!.claude/
.claude/**
!.claude/skills/
!.claude/skills/**
.claude/settings.local.json

114
CLAUDE.md Normal file
View file

@ -0,0 +1,114 @@
# 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