diff --git a/AGENTS.md b/AGENTS.md index 11cc7b407..fc0c95fdb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,1733 +1,335 @@ # AI Agent Development Guide for ZoneMinder > **Note**: This file guides AI coding agents (Claude Code, GitHub Copilot, Cursor, etc.) working on ZoneMinder. -> CLAUDE.md is a symlink to this file - different agents look for different filenames. +> CLAUDE.md is a symlink to this file. ## Quick Reference (MANDATORY RULES) -1. **Testing First**: Write tests BEFORE/DURING implementation - NEVER skip (see Testing Requirements) -2. **Build System**: CMake with C++17, out-of-source builds required -3. **Feature Workflow**: GitHub Issue → Feature Branch → Implement FULLY → Tests Pass → Get Approval → Merge to master -4. **Commits**: Conventional format (`feat:`/`fix:`/`test:`), reference issues (`refs #n` or `fixes #n`) -5. **Pre-Commit Checklist**: Tests pass, build succeeds, linting clean, no warnings -6. **Language-Specific Tests**: C++ (Catch2/ctest), JavaScript (ESLint in CI), PHP (manual + future automation) +1. **Testing First**: Write tests BEFORE/DURING implementation - NEVER skip. Tests written "later" never get written. +2. **Build System**: CMake with C++17, out-of-source builds in `build/`. In-source builds pollute the repo. +3. **Feature Workflow**: GitHub Issue -> Feature Branch -> Implement FULLY -> Tests Pass -> Get Approval -> Merge to master. Feature branches keep master stable. +4. **Commits**: Conventional format (`feat:`/`fix:`/`test:`), reference issues (`refs #n` or `fixes #n`). Enables automated changelog. +5. **Pre-Commit**: Tests pass, build succeeds, linting clean, no warnings. +6. **Never merge without user approval. Never leave features half-implemented.** --- ## What is ZoneMinder? -ZoneMinder is an integrated Linux-based CCTV surveillance system that provides capture, analysis, recording, and monitoring of video cameras. It consists of: +Linux-based CCTV surveillance system: capture, analysis, recording, and monitoring of video cameras. -- **C++ capture/analysis/streaming daemons** - Core video processing -- **PHP web interface with REST API** - User interface and API endpoints -- **Perl system management scripts** - Daemon control and maintenance -- **MySQL database** - Configuration and event storage +- **C++ daemons** (`src/`) - Capture (`zmc`), analysis (`zma`), streaming (`zms`), utility (`zmu`) +- **PHP web interface** (`web/`) - Bootstrap + jQuery UI, AJAX endpoints in `web/ajax/`, views in `web/views/` +- **REST API** (`web/api/`) - CakePHP 2.x, controllers in `web/api/app/Controller/`, JWT auth +- **Perl scripts** (`scripts/`) - Daemon control (`zmdc.pl`), migrations (`zmupdate.pl`), filtering (`zmfilter.pl`) +- **MySQL database** (`db/`) - Schema in `db/zm_create.sql.in`, migrations in `db/zm_update-*.sql` (60+ versions) -**Project Scale:** -- 86+ C++ source files -- 31+ database tables -- Multi-language codebase (C++17, PHP, JavaScript, Perl) -- Multi-platform support (Linux, FreeBSD) -- 15+ years of development history +--- + +## Architecture + +### Data Flow + +``` +Camera -> zmc (capture) -> Shared Memory -> zma (analysis) -> Event Recording + | | + zms (streaming) Database + Disk + | | + Web Browsers <- Web Interface/API <- MySQL Storage +``` + +### Key Patterns + +- **Shared Memory**: `zmc` writes frames to `/dev/shm`; `zma` and `zms` read from same buffers. Zero-copy for performance — this is why ZM can handle many cameras on modest hardware. +- **Monitor-Centric**: `Monitor` class (`src/zm_monitor.cpp/h`) is the central orchestrator. One monitor = one DB row = one set of daemons. Most changes to camera handling flow through this class. +- **Pluggable Cameras**: Abstract `Camera` base with: `LocalCamera` (V4L2), `RemoteCameraRTSP`, `RemoteCameraHTTP`, `FFmpegCamera`, `LibVLCCamera`, `LibVNCCamera`. Add new camera types by subclassing Camera. +- **Event-Driven Recording**: Motion detection triggers `Event` objects with pre/post alarm buffers. Lifecycle: Create -> Record -> Close -> Archive/Delete. Events are the core unit of recorded footage. +- **Multi-Server Clustering**: Database-coordinated distributed architecture with shared monitors and storage. + +### Directory Structure (Key Paths) + +``` +src/ C++ core (86+ source files): zm_monitor.*, zm_camera.*, zm_event.*, zm_zone.*, zm_image.*, zm_ffmpeg*.* +web/ PHP web interface + ajax/ AJAX handlers + includes/ PHP libraries and functions + views/ UI templates + skins/ Themes (classic skin) + js/, css/ Frontend assets + api/app/Controller/ CakePHP REST API controllers + api/app/Model/ CakePHP REST API models +scripts/ Perl system management (.in templates) +db/ Schema (zm_create.sql.in) and migrations (zm_update-*.sql) +tests/ Catch2 unit tests + test data +misc/ Server configs (apache, nginx, systemd) +dep/ Vendored deps (catch2, jwt-cpp) +.github/workflows/ CI/CD pipelines +``` --- ## Development Workflow (MANDATORY) -### When the user requests a new feature, follow this workflow: +### For every feature or bug fix: -#### 1. Create GitHub Issue +1. **Create GitHub Issue**: `gh issue create --title "..." --label enhancement|bug` +2. **Create Feature Branch**: `git checkout -b -` from master +3. **Write failing test first** (TDD) +4. **Implement** - follow existing patterns, keep changes minimal +5. **Build & test** - must all pass (see Build and Testing sections) +6. **Commit** in logical chunks with conventional messages +7. **Request user approval** - never merge without it +8. **After approval**: merge to master, delete branch, push, verify issue closes -- Create a GitHub issue for the feature request using `gh issue create` -- Label it as `enhancement` -- Include clear description of what the feature should do -- Example: - ```bash - gh issue create --title "Add event favorites feature" \ - --body "Allow users to mark events as favorites and filter by favorites" \ - --label "enhancement" - ``` +### Technology-Specific Notes -#### 2. Create Feature Branch +- **C++ changes** (`src/`): Rebuild required, run ctest. Daemons must be restarted to pick up changes. +- **PHP/JS changes** (`web/`): No rebuild needed — PHP is interpreted, changes are live immediately. Test in browser + ESLint. +- **Database schema** (`db/`): Create migration file `zm_update-X.X.X.sql` for existing installs, also update `db/zm_create.sql.in` for fresh installs. Both must result in the same schema. +- **Perl scripts** (`scripts/`): Edit `.in` template files (NOT generated scripts). cmake substitutes `@ZM_*@` variables to produce the final scripts. +- **API changes** (`web/api/`): Clear CakePHP cache (`tmp/cache/`) if you change models or routes. Test endpoints with curl. -- Create a new branch from master with descriptive name -- Branch naming: `-` (e.g., `456-fix-rtsp-crash`) -- Example: - ```bash - git checkout master - git pull - git checkout -b 123-event-favorites - ``` +### Example Workflow -#### 3. Implement Feature Completely - -**CRITICAL**: Implement the ENTIRE feature - do not stop in the middle. - -**Implementation Steps:** - -a. **Write failing test first** (test-driven development) - - C++: Add Catch2 test in `tests/` - - PHP/JS: Manual testing checklist (automated tests future enhancement) - -b. **Implement code to pass test** - - Follow existing code patterns - - Keep changes minimal and focused - - Don't add unrelated "improvements" - -c. **Build verification** (C++ changes): - ```bash - cd build - cmake --build . # Must succeed with no errors - ``` - -d. **Test verification**: - ```bash - # C++ unit tests (if BUILD_TEST_SUITE=ON) - ctest - # Or run test binary directly - ./tests/tests - - # JavaScript linting - npx eslint --ext .js.php,.js . - - # Manual testing for PHP/web changes - # - Test in browser - # - Check browser console for errors - # - Test API endpoints if applicable - ``` - -e. **Commit in logical chunks** with conventional commit messages: - ```bash - git add - git commit -m "feat: add favorites toggle to event view refs #123" - # More commits as needed for different logical components - ``` - -**Technology-Specific Notes:** -- **C++ changes** (`src/`): Rebuild required, run ctest if tests enabled -- **PHP/JS changes** (`web/`): No rebuild needed, test manually in browser -- **Database schema** (`db/`): Create migration file `zm_update-X.X.X.sql` -- **Perl scripts** (`scripts/`): Edit `.in` template files, rerun cmake to generate scripts -- **API changes** (`web/api/`): Clear CakePHP cache if needed, test endpoints - -#### 4. Request User Feedback - -- Once implementation is complete and all tests pass, ask user for feedback -- DO NOT merge or push without user approval -- Example: "Feature implementation complete. All tests passing. Ready for your review." - -#### 5. Merge and Cleanup (After User Approval Only) - -- Merge feature branch to master -- Delete the feature branch (local and remote) -- Reference the issue in final commit/merge: `fixes #` -- Push to master -- Verify issue is automatically closed - -**Example Complete Workflow:** ```bash -# 1. Create issue -gh issue create --title "Add dark mode toggle" \ - --body "Add UI toggle for dark mode theme" \ - --label "enhancement" -# Note the issue number (e.g., #42) +gh issue create --title "Add event favorites" --label enhancement +# Note issue number, e.g. #42 +git checkout master && git pull && git checkout -b 42-event-favorites -# 2. Create branch -git checkout master -git pull -git checkout -b 42-dark-mode - -# 3. Implement + test + commit -# ... write tests first ... -# ... implement feature ... +# Write test first, implement, build & test cd build && cmake --build . && ctest -git add web/skins/classic/css/dark-mode.css web/includes/functions.php -git commit -m "feat: add dark mode CSS and theme switcher refs #42" -git add tests/zm_theme.cpp -git commit -m "test: add dark mode toggle tests refs #42" - -# 4. Ask user for approval -# "Feature implementation complete. Tests passing. Ready for review." -# (Wait for user confirmation) - -# 5. After approval, merge and cleanup -git checkout master -git merge 42-dark-mode -git push origin master -git branch -d 42-dark-mode -git push origin --delete 42-dark-mode -# Verify issue #42 is closed -``` - -**Important Notes:** -- Never merge to master without user approval -- Never leave a feature half-implemented -- Always include tests before requesting approval -- Feature branches keep master stable and allow for review - ---- - -## Testing Requirements (MANDATORY - No Exceptions) - -### Test-First Development Workflow - -**Rule**: Write tests BEFORE or DURING implementation, NEVER skip tests. - -**Why**: Tests written "later" are usually never written. Tests verify code actually works. - -**Workflow**: -1. Understand the bug/feature requirement -2. Write a failing test that reproduces the issue or validates the feature -3. Implement the fix/feature -4. Run tests - verify they now PASS -5. Run full test suite to check for regressions -6. Only then commit - -### C++ Unit Tests (Catch2 Framework) - -**Location**: `tests/` directory - -**Enable and Build Tests**: -```bash -# From clean build directory -mkdir build && cd build -cmake -DBUILD_TEST_SUITE=ON .. -cmake --build . - -# Run all tests -ctest - -# Run test binary directly with more output -./tests/tests - -# Run specific test by name -./tests/tests "[Box]" - -# List all available tests -./tests/tests --list-tests - -# Run tests excluding CI-skipped tests -./tests/tests "~[notCI]" -``` - -**Existing Test Modules** (7 files in `tests/`): -- `zm_box.cpp` - Bounding box geometry (Box class) -- `zm_comms.cpp` - Network communication (pipes, sockets, TLS) -- `zm_crypt.cpp` - Cryptography and JWT token validation -- `zm_font.cpp` - Font rendering -- `zm_poly.cpp` - Polygon geometry and intersection -- `zm_utils.cpp` - Utility functions -- `zm_vector2.cpp` - 2D vector mathematics - -**When to Add C++ Tests**: -- ✅ New functionality → Write new test file or add to existing -- ✅ Bug fixes → Write test that reproduces bug FIRST -- ✅ Refactoring → Ensure existing tests still pass -- ✅ Changes to existing functionality → Update tests BEFORE changing code -- ✅ New components → Create new test file as you build -- ✅ Utility functions → Test all logic paths and edge cases - -**Test Framework Details**: -- Framework: Catch2 (modern C++ test framework) -- Custom header: `tests/zm_catch2.h` with helper macros -- Main entry: `tests/main.cpp` with `CATCH_CONFIG_MAIN` -- Test data: `tests/data/fonts/` directory for fixtures -- CMake integration: `catch_discover_tests()` for automatic test discovery - -**What to Test**: -- Happy path (normal usage) -- Edge cases (empty arrays, null pointers, boundary conditions) -- Error cases (network failures, invalid input, missing data) -- State changes (verify before/after behavior) -- ZoneMinder-specific examples: - - Camera connection edge cases - - Event recording state transitions - - Shared memory buffer handling - - Image format conversions - - Zone polygon intersections - -### JavaScript/PHP Linting - -**ESLint Configuration**: -- Config files: `.eslintrc.js` (legacy) and `eslint.config.js` (flat config) -- Style guide: Google JavaScript Style Guide -- Plugins: eslint-plugin-html, eslint-plugin-php-markup -- Handles: Browser JavaScript and inline JS within PHP files - -**Run Linting**: -```bash -# Lint all JavaScript (if Node.js/eslint installed) npx eslint --ext .js.php,.js . -# Lint specific directory -npx eslint web/js/ +# Commit +git add +git commit -m "feat: add favorites toggle to event view refs #42" -# Fix auto-fixable issues -npx eslint --fix web/ +# Ask user for approval, then after approval: +git checkout master && git merge 42-event-favorites +git push origin master +git branch -d 42-event-favorites && git push origin --delete 42-event-favorites ``` -**CI Integration**: -- ESLint runs automatically in GitHub Actions (`.github/workflows/ci-eslint.yml`) -- Triggers on all pushes and PRs to master -- Must pass for PR approval - -### PHP/API Testing - -**Current State**: -- Framework: CakePHP 2.x test framework (in API) -- Location: `web/api/app/Plugin/Crud/Test/` -- Infrastructure exists but NOT run in CI pipeline -- Manual testing required for API endpoints - -**Manual API Testing Checklist**: -- Test endpoints in browser or with curl/Postman -- Verify JSON response structure -- Test authentication (session and JWT) -- Check error handling (invalid input, missing data) -- Verify database changes persist correctly - -**Future Enhancement**: Integrate CakePHP tests into CI pipeline - -### Database Migration Testing - -**Migration Framework**: -- Location: `db/` directory -- Initial schema: `db/zm_create.sql.in` -- Incremental migrations: `db/zm_update-X.X.X.sql` (60+ versions) -- Update script: `scripts/zmupdate.pl.in` - -**Testing Database Changes**: -```bash -# Check for available updates -sudo zmupdate.pl --check - -# Apply pending migrations -sudo zmupdate.pl - -# Force specific version upgrade (testing) -sudo zmupdate.pl -v 1.37.32 - -# Freshen config in database -sudo zmupdate.pl --freshen -``` - -**When Creating Migrations**: -- Create new `db/zm_update-X.X.X.sql` file -- Test upgrade path from previous version -- Test fresh install vs. migration (both should result in same schema) -- Document any manual steps required -- Test on supported databases (MySQL, MariaDB) - -### CI/CD Testing (GitHub Actions) - -**Current CI Pipeline** (`.github/workflows/`): - -1. **ESLint** (`ci-eslint.yml`) - JavaScript/PHP linting ✅ -2. **Multi-platform builds**: - - Debian Bookworm (`ci-bookworm.yml`) - 4 config matrix - - Debian Bullseye (`ci-bullseye.yml`) - 4 config matrix - - Ubuntu Focal (`ci-focal.yml`) - 2 config matrix - - CentOS/RHEL 8 (`ci-centos-8.yml`) - Rocky Linux -3. **CodeQL Security Analysis** (`codeql-analysis.yml`) - C++ and JavaScript -4. **Package Building** (`build-native-packages.yml`) - Multi-distro .deb packages - -**CI Build Matrix**: -- Crypto backends: GnuTLS vs. OpenSSL -- JWT backends: libjwt vs. jwt_cpp -- Platforms: Debian, Ubuntu, CentOS/RHEL -- Architectures: x86_64 and ARM64 (aarch64) - -**Important CI Note**: -- ⚠️ **Unit tests are DISABLED in CI** (`BUILD_TEST_SUITE=0`) -- CI focuses on build verification and linting -- Tests are commented out in workflows (e.g., `# ./tests/tests "~[notCI]"`) -- When you run tests locally, you're going beyond current CI requirements ✅ - -**CI Configuration Options**: -```bash -# Typical CI build flags -cmake \ - -DCMAKE_BUILD_TYPE=Release \ - -DBUILD_TEST_SUITE=0 \ - -DBUILD_MAN=0 \ - -DENABLE_WERROR=1 \ - .. -``` - -### Integration Testing - -**Current State**: No formal integration test suite - -**Manual Integration Testing**: -- Test full workflow: Monitor creation → Event capture → Playback -- Test daemon lifecycle: Start → Stop → Restart -- Test web interface flows: Login → Monitor config → Event filtering -- Test API workflows: Authentication → CRUD operations -- Test multi-server scenarios if applicable - -### Pre-Test Checklist - -**Before stating "Done" or committing**: -- [ ] ALL applicable tests have been written (not just build) -- [ ] ALL tests have been run (ctest for C++, ESLint for JS) -- [ ] ALL tests PASS (not just "no errors") -- [ ] State which tests were run and their results - -**Never Commit or Claim Complete If**: -- ❌ Tests are failing -- ❌ Tests don't exist for new/changed functionality -- ❌ You haven't actually run the tests -- ❌ Build fails -- ❌ You only ran build but not unit/linting tests -- ❌ ESLint reports errors - --- ## Build System -ZoneMinder uses **CMake** as its build system with **C++17** standard. - -### Basic Build Commands - ```bash -# Create build directory (out-of-source build required) -mkdir build -cd build - -# Configure with CMake (basic) -cmake .. - -# Or configure with custom options -cmake \ - -DCMAKE_BUILD_TYPE=Debug \ - -DBUILD_TEST_SUITE=ON \ - -DZM_WEBDIR=/usr/share/zoneminder/www \ - -DZM_CONTENTDIR=/var/lib/zoneminder \ - .. - -# Build the project -cmake --build . - -# Build with verbose output (see actual commands) -cmake --build . --verbose - -# Build specific target -cmake --build . --target zmc - -# Install (requires appropriate permissions) -sudo cmake --build . --target install -``` - -### Important CMake Configuration Options - -**Build Types**: -- `CMAKE_BUILD_TYPE=Release` - Optimized build (default), `-O2` optimization -- `CMAKE_BUILD_TYPE=Debug` - Debug symbols, `-g` flag -- `CMAKE_BUILD_TYPE=Optimised` - Custom optimized build - -**Testing & Development**: -- `BUILD_TEST_SUITE=ON` - Enable Catch2 unit tests (default: OFF) -- `BUILD_MAN=ON` - Build man pages (default: ON) -- `ENABLE_WERROR=ON` - Treat warnings as errors (used in CI) - -**Debugging & Analysis**: -- `ASAN=ON` - Build with AddressSanitizer for memory debugging (default: OFF) -- `TSAN=ON` - Build with ThreadSanitizer for thread debugging (default: OFF, mutually exclusive with ASAN) - -**Feature Toggles**: -- `ZM_ONVIF=ON` - Enable ONVIF camera support (default: ON) -- `ZM_NO_LIBVLC=ON` - Skip libVLC checks (default: OFF) -- `ZM_NO_CURL=ON` - Skip cURL checks (default: OFF) - -**Platform & Paths**: -- `ZM_TARGET_DISTRO=` - Set platform: `FreeBSD`, `fc` (Fedora), `el` (RHEL/CentOS), `OS13` (OpenSUSE) -- `ZM_WEBDIR=` - Web root directory -- `ZM_CONTENTDIR=` - Content storage directory -- `ZM_LOGDIR=` - Log file directory -- `ZM_RUNDIR=` - Runtime PID files directory - -**Crypto & JWT Backends**: -- `ZM_CRYPTO_BACKEND=` - `openssl` or `gnutls` -- `ZM_JWT_BACKEND=` - `libjwt` or `jwt_cpp` - -### Build Examples - -```bash -# Debug build with tests and AddressSanitizer -cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TEST_SUITE=ON -DASAN=ON .. -cmake --build . - -# Release build for FreeBSD -cmake -DCMAKE_BUILD_TYPE=Release -DZM_TARGET_DISTRO=FreeBSD .. -cmake --build . - -# CI-style build (strict warnings) -cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_WERROR=1 -DBUILD_TEST_SUITE=0 .. -cmake --build . -``` - -### C++ Code Standards - -- **C++17** standard required -- Compiler flags: `-O2` for release, `-g` for debug -- Large file support: `-D_FILE_OFFSET_BITS=64` -- ARM NEON optimizations auto-detected on ARM platforms -- Warning level: High (use `-DENABLE_WERROR=1` to enforce) - ---- - -## Architecture Overview - -### Core Components - -1. **C++ Daemons** (`src/`): - - `zmc` - **Capture daemon** (one per monitor) - captures frames from cameras - - `zma` - **Analysis daemon** - motion detection and event triggering - - `zms` - **Streaming server** - delivers live/recorded video to web clients - - `zmu` - **Utility program** - command-line monitor management - -2. **Web Interface** (`web/`): - - PHP-based user interface - - Bootstrap + jQuery frontend - - AJAX endpoints in `web/ajax/` - - View templates in `web/views/` - - Multiple skins in `web/skins/` - -3. **REST API** (`web/api/`): - - CakePHP 2.x-based modern API - - Controllers in `web/api/app/Controller/` - - Models in `web/api/app/Model/` - - JSON responses for programmatic access - - JWT authentication support - -4. **Perl Scripts** (`scripts/`): - - `zmdc.pl` - Daemon control and supervision - - `zmaudit.pl` - Database maintenance and consistency checks - - `zmupdate.pl` - Schema migrations and upgrades - - `zmfilter.pl` - Event filtering and automated actions - - `zmwatch.pl` - Process health monitoring - - `zmtrigger.pl` - External event triggering - - `zmonvif-probe.pl` - ONVIF camera discovery - -5. **Database** (`db/`): - - MySQL/MariaDB schema with 31+ tables - - Incremental migration scripts: `zm_update-*.sql` - - Core tables: Monitors, Events, Frames, Zones, Users, Storage, Servers - -### Key Architectural Patterns - -**Shared Memory Architecture**: -- Capture daemons write frames to shared memory (`/dev/shm` by default) -- Analysis and streaming daemons read from the same buffers -- Zero-copy efficiency for high-performance video processing - -**Monitor-Centric Design**: -- The `Monitor` class (`src/zm_monitor.cpp/h`) is the central orchestrator -- Manages capture, analysis, recording, and streaming for each camera -- One monitor = one database row = one set of daemons - -**Pluggable Camera Types**: -- Abstract `Camera` base class with implementations: - - `LocalCamera` - V4L2 devices (webcams, capture cards) - - `RemoteCameraRTSP` - RTSP network streams - - `RemoteCameraHTTP` - HTTP image URLs (MJPEG, snapshots) - - `FFmpegCamera` - FFmpeg-based (supports 100+ formats) - - `LibVLCCamera` - VLC media playback - - `LibVNCCamera` - VNC screen capture - -**Event-Driven Recording**: -- Motion detection triggers `Event` objects -- Events manage recording of video segments to disk and database -- Configurable pre/post alarm recording buffers -- Event lifecycle: Create → Record frames → Close → Archive/Delete - -**Multi-Server Clustering**: -- Database-coordinated distributed architecture -- Multiple ZoneMinder servers can share monitors and storage -- Server load balancing and failover support - -### Data Flow - -``` -Camera → zmc (capture) → Shared Memory → zma (analysis) → Event Recording - ↓ ↓ - zms (streaming) Database + Disk - ↓ ↓ - Web Browsers ← Web Interface/API ← MySQL Storage -``` - -**Detailed Flow**: -1. **Capture**: `zmc` connects to camera, writes frames to shared memory buffer -2. **Analysis**: `zma` reads from shared memory, performs motion detection on zones -3. **Event Trigger**: Motion detected → Create Event → Start recording -4. **Storage**: Frames written to disk in event directories, metadata to MySQL -5. **Streaming**: `zms` reads from shared memory or disk to deliver video to browsers -6. **Web UI**: PHP interface queries MySQL, triggers streaming via `zms`, displays events -7. **API**: CakePHP REST API provides programmatic access to all functionality - ---- - -## Directory Structure - -``` -ZoneMinder/ -├── src/ # C++ core binaries (86+ source files) -│ ├── zmc.cpp # Capture daemon entry point -│ ├── zma.cpp # Analysis daemon entry point -│ ├── zms.cpp # Streaming server entry point -│ ├── zmu.cpp # Utility program entry point -│ ├── zm_monitor.* # Monitor orchestration (core class) -│ ├── zm_camera.* # Camera base classes and implementations -│ ├── zm_event.* # Event recording management -│ ├── zm_zone.* # Motion detection zones -│ ├── zm_image.* # Image processing and manipulation -│ ├── zm_ffmpeg*.* # FFmpeg integration -│ ├── zm_rtsp*.* # RTSP server support -│ ├── zm_box.* # Bounding box geometry -│ ├── zm_poly.* # Polygon geometry -│ ├── zm_crypt.* # Cryptography utilities -│ └── zm_utils.* # General utilities -│ -├── web/ # Web interface -│ ├── index.php # Main entry point -│ ├── ajax/ # AJAX handlers for async requests -│ ├── includes/ # PHP libraries and functions -│ ├── views/ # UI templates (HTML/PHP) -│ ├── skins/ # Themes (classic, dark, etc.) -│ ├── js/ # JavaScript files -│ ├── css/ # Stylesheets -│ └── api/ # CakePHP REST API -│ ├── app/ -│ │ ├── Controller/ # API controllers -│ │ ├── Model/ # API models -│ │ └── Plugin/ # CakePHP plugins -│ └── webroot/ # API entry point -│ -├── scripts/ # System management (Perl) -│ ├── zmdc.pl.in # Daemon supervisor -│ ├── zmaudit.pl.in # Database maintenance -│ ├── zmfilter.pl.in # Event filtering -│ ├── zmupdate.pl.in # Schema migrations -│ ├── zmwatch.pl.in # Process monitoring -│ ├── zmtrigger.pl.in # External triggering -│ └── ZoneMinder/ # Perl modules -│ ├── ConfigData.pm # Configuration management -│ └── Logger.pm # Logging utilities -│ -├── db/ # Database schema -│ ├── zm_create.sql.in # Initial schema template -│ └── zm_update-*.sql # Incremental migrations (60+ files) -│ -├── tests/ # Unit tests (Catch2) -│ ├── main.cpp # Test runner entry point -│ ├── zm_catch2.h # Custom Catch2 helpers -│ ├── zm_box.cpp # Box geometry tests -│ ├── zm_comms.cpp # Communications tests -│ ├── zm_crypt.cpp # Cryptography tests -│ ├── zm_font.cpp # Font rendering tests -│ ├── zm_poly.cpp # Polygon tests -│ ├── zm_utils.cpp # Utils tests -│ ├── zm_vector2.cpp # Vector math tests -│ └── data/ # Test fixtures -│ -├── docs/ # Sphinx documentation -│ ├── userguide/ # User documentation -│ ├── installationguide/ # Installation docs -│ └── contributing.rst # Contributor guide -│ -├── misc/ # Server configs -│ ├── apache.conf # Apache configuration -│ ├── nginx.conf # Nginx configuration -│ └── zoneminder.service # systemd unit file -│ -├── onvif/ # ONVIF camera support -│ └── proxy/ # ONVIF SOAP proxy -│ -├── utils/ # Development utilities -│ └── packpack/ # Packaging scripts -│ -├── dep/ # Vendored dependencies -│ ├── catch/ # Catch2 test framework -│ └── jwt-cpp/ # JWT library -│ -├── .github/ # GitHub configuration -│ └── workflows/ # CI/CD pipelines -│ -├── CMakeLists.txt # Root CMake configuration -├── CONTRIBUTING.md # Contribution guidelines -├── AGENTS.md # This file (AI agent guide) -└── CLAUDE.md # Symlink to AGENTS.md -``` - ---- - -## Code Quality & Standards - -### Language-Specific Guidelines - -#### C++ (`src/`) - -**Standards**: -- Language: C++17 -- Style: Follow existing code patterns in the file/module -- Memory: Use RAII, smart pointers (`std::unique_ptr`, `std::shared_ptr`) where appropriate -- Error handling: Exceptions for exceptional cases, return codes for expected errors -- Logging: Use `Logger` class with levels: Debug, Info, Warning, Error, Fatal - -**Example Logging**: -```cpp -Debug(1, "Monitor %s: Capturing frame %d", name.c_str(), frame_count); -Info("Started capture daemon for monitor %d", id); -Warning("Failed to connect, retrying in %d seconds", retry_delay); -Error("Unable to open camera device: %s", strerror(errno)); -Fatal("Critical error in shared memory: %s", error_msg); -``` - -**Testing**: Catch2 framework -```cpp -#include "zm_catch2.h" - -TEST_CASE("Box intersection", "[Box]") { - Box box1(10, 10, 20, 20); - Box box2(15, 15, 25, 25); - - REQUIRE(box1.Intersects(box2)); - Box intersection = box1.Intersection(box2); - REQUIRE(intersection.Width() == 5); -} -``` - -#### PHP (`web/`, `web/api/`) - -**Standards**: -- Style: PSR-12 where practical, follow existing conventions -- Security: - - **Validate ALL user input** - - Use prepared statements for database queries - - Sanitize output (htmlspecialchars, json_encode) - - CSRF protection on forms -- API: CakePHP 2.x framework in `web/api/` -- Sessions: Manage via ZoneMinder session handler - -**Example Secure Query**: -```php -// Good - prepared statement -$stmt = $dbConn->prepare('SELECT * FROM Monitors WHERE Id = ?'); -$stmt->execute(array($monitorId)); - -// Bad - SQL injection vulnerable -$sql = "SELECT * FROM Monitors WHERE Id = $monitorId"; -``` - -**Testing**: Manual testing + future CakePHP test automation - -#### JavaScript (`web/js/`, inline in PHP) - -**Standards**: -- Style: Google JavaScript Style Guide (configured in ESLint) -- Linting: ESLint with html and php-markup plugins -- Framework: jQuery + Bootstrap (legacy codebase) -- Modern JS: Can use ES6+ features where browser support allows - -**ESLint Configuration** (`.eslintrc.js`): -- Extends: google -- Relaxed rules: camelCase, max-len, jsdoc requirements -- Handles: Browser globals, jQuery, inline JS in PHP files - -**Linting**: -```bash -npx eslint --ext .js.php,.js . -npx eslint --fix web/js/ # Auto-fix issues -``` - -**Testing**: ESLint in CI (`.github/workflows/ci-eslint.yml`) - -#### Perl (`scripts/`) - -**Standards**: -- Edit: `.in` template files, NOT generated scripts -- Modules: Use `ZoneMinder::` modules where appropriate -- Error handling: Follow existing patterns with proper error messages -- Logging: Use `ZoneMinder::Logger` - -**Example**: -```perl -use ZoneMinder; -use ZoneMinder::Logger; - -Info("Starting daemon control"); -if (!daemonControl('start', $daemon)) { - Error("Failed to start daemon: $!"); -} -``` - -**Rebuild**: After editing `.in` files, rerun cmake to regenerate scripts - ---- - -## Debugging & Performance Tools - -### Debugging C++ Code - -**Basic Debugging with GDB**: -```bash -# Build with debug symbols -cd build -cmake -DCMAKE_BUILD_TYPE=Debug .. -cmake --build . - -# Run under debugger -gdb ./src/zmc -(gdb) break zm_monitor.cpp:123 -(gdb) run -m 1 -(gdb) backtrace -(gdb) print variable_name -``` - -**AddressSanitizer (Memory Debugging)**: -```bash -# Build with ASan -cmake -DCMAKE_BUILD_TYPE=Debug -DASAN=ON .. -cmake --build . - -# Run normally - ASan will report memory issues -./src/zmc -m 1 -# ASan reports: leaks, use-after-free, buffer overflows, etc. -``` - -**ThreadSanitizer (Thread Debugging)**: -```bash -# Build with TSan (mutually exclusive with ASan) -cmake -DCMAKE_BUILD_TYPE=Debug -DTSAN=ON .. -cmake --build . - -# Run normally - TSan will report threading issues -./src/zma -m 1 -# TSan reports: data races, deadlocks, thread leaks, etc. -``` - -### Runtime Logging - -**Log Configuration**: -- Web UI: **Options → System → Logging** - - `LOG_LEVEL_FILE` - File logging level (None to Debug9) - - `LOG_LEVEL_DATABASE` - Database logging level - - `LOG_LEVEL_SYSLOG` - Syslog logging level - - `LOG_DEBUG_TARGET` - Target specific component for debugging - -**Log Locations**: -- Default: `/var/log/zm/` (configurable via `ZM_LOGDIR`) -- Files: `zmc_m1.log`, `zma_m2.log`, `zms.log`, etc. -- Syslog: Check `/var/log/syslog` or `journalctl -u zoneminder` - -**Debug Specific Components**: -```bash -# Debug specific monitor capture daemon -# Set in web UI: LOG_DEBUG_TARGET = _zmc_m5 -# Or via environment: -export ZM_DBG_LEVEL=9 -export ZM_DBG_LOG=/tmp/zmc_debug.log -./src/zmc -m 5 - -# Debug with stdout output -export ZM_DBG_PRINT=1 -./src/zmc -m 5 -``` - -**Runtime Log Level Control**: -```bash -# Send USR1 signal to increase log level -kill -USR1 - -# Send USR2 signal to decrease log level -kill -USR2 -``` - -### Performance Profiling - -**Built-in Performance Stats**: -- Monitor stats available via web UI -- Frame capture rates, analysis times -- Database query timing in debug logs - -**External Profiling Tools**: -```bash -# Valgrind for memory profiling -valgrind --leak-check=full ./src/zmc -m 1 - -# Perf for CPU profiling (Linux) -perf record -g ./src/zmc -m 1 -perf report - -# Callgrind for call graph analysis -valgrind --tool=callgrind ./src/zmc -m 1 -kcachegrind callgrind.out.* -``` - -### Browser Debugging - -**JavaScript Console**: -- Browser Dev Tools (F12) -- Check console for JavaScript errors -- Network tab for AJAX request debugging -- Monitor WebSocket connections for streaming - -**PHP Debugging**: -- Enable PHP error display: `php.ini` → `display_errors = On` -- Check PHP error logs: `/var/log/apache2/error.log` or `/var/log/nginx/error.log` -- Use `error_log()` function for debug output -- Xdebug for step-through debugging (optional) - ---- - -## Commit Standards - -### Commit Message Format - -**Use conventional commit format**: -- `feat:` - New feature -- `fix:` - Bug fix -- `docs:` - Documentation changes -- `test:` - Test additions or modifications -- `chore:` - Maintenance tasks (dependencies, config) -- `refactor:` - Code restructuring without behavior change -- `perf:` - Performance improvements -- `style:` - Code style changes (formatting, no logic change) - -**Issue References**: -- `refs #123` - Reference issue without closing -- `fixes #123` - Close issue when commit is merged - -**Commit Message Guidelines**: -- Be detailed and descriptive (no vague summaries) -- Split unrelated changes into separate commits (one logical change per commit) -- Avoid superlative language (no "comprehensive", "critical", "major", "massive") -- Keep messages factual and objective -- Use imperative mood ("add feature" not "added feature") - -**Examples**: - -✅ **Good**: -``` -feat: add RTSP reconnection logic to RemoteCameraRTSP refs #42 - -Implements automatic reconnection when RTSP stream drops. Adds -exponential backoff with configurable retry delay. Includes new -Monitor setting for max retry attempts. -``` - -✅ **Good**: -``` -fix: resolve shared memory leak in Monitor class fixes #123 - -Shared memory segments were not being properly released when monitor -was disabled. Added cleanup in Monitor destructor. -``` - -✅ **Good**: -``` -test: add Catch2 tests for Polygon intersection - -Added test cases for polygon overlap detection including edge cases: -- Adjacent polygons (touching edges) -- Nested polygons -- Non-intersecting polygons -``` - -❌ **Bad**: -``` -fix: comprehensive camera improvements - -Fixed various issues. -``` - -❌ **Bad**: -``` -feat: massive critical overhaul of event system - -Improved everything. -``` - -### Committing Multiple Changes - -**When you have multiple logical changes, create separate commits**: -```bash -# Change 1: Add feature -git add src/zm_monitor.cpp src/zm_monitor.h -git commit -m "feat: add auto-reconnect for camera failures refs #42" - -# Change 2: Add tests -git add tests/zm_monitor.cpp -git commit -m "test: add monitor reconnection tests refs #42" - -# Change 3: Update docs -git add docs/userguide/monitors.rst -git commit -m "docs: document auto-reconnect feature refs #42" -``` - ---- - -## Pre-Commit Checklist - -### ALL Changes (MANDATORY - No Exceptions) - -- [ ] **Tests written/updated** BEFORE or DURING implementation -- [ ] **Build succeeds**: `cmake --build .` (for C++ changes) -- [ ] **Tests pass**: - - [ ] C++ unit tests: `ctest` or `./tests/tests` - - [ ] JavaScript linting: `npx eslint --ext .js.php,.js .` - - [ ] Manual testing (for PHP/web changes) -- [ ] **No warnings** from compiler or linter -- [ ] **Code follows existing patterns** in the file/module -- [ ] **Commit messages** follow conventional format -- [ ] **Issue referenced** in commit message (`refs #n` or `fixes #n`) - -### Before Stating "Done" or Requesting Approval - -- [ ] ALL applicable tests have been run (not just build) -- [ ] ALL tests PASS (not just "no errors") -- [ ] State which tests were run and their results -- [ ] Feature is COMPLETE (not half-implemented) -- [ ] Documentation updated if adding new features - -### Never Commit or Claim Complete If - -- ❌ Tests are failing -- ❌ Tests don't exist for new/changed functionality -- ❌ You haven't actually run the tests -- ❌ Build fails -- ❌ Compiler warnings exist -- ❌ ESLint reports errors -- ❌ You only ran build but not unit/linting tests -- ❌ Feature is incomplete or partially implemented - ---- - -## Common Development Tasks - -### Adding a New C++ Feature - -```bash -# 1. Create issue and branch -gh issue create --title "Add motion mask feature" --label enhancement -git checkout -b 123-motion-mask - -# 2. Write failing test first -# Edit tests/zm_zone.cpp - add test for new feature - -# 3. Implement feature -# Edit src/zm_zone.cpp, src/zm_zone.h - -# 4. Build and test -cd build -cmake --build . -./tests/tests "[Zone]" # Run zone tests specifically - -# 5. Commit -git add tests/zm_zone.cpp src/zm_zone.cpp src/zm_zone.h -git commit -m "feat: add motion mask support to Zone class refs #123" - -# 6. Request approval -# Ask user for review - -# 7. After approval, merge -git checkout master -git merge 123-motion-mask -git push origin master -git branch -d 123-motion-mask -``` - -### Fixing a Bug - -```bash -# 1. Create issue and branch -gh issue create --title "RTSP stream freezes after 1 hour" --label bug -git checkout -b 456-rtsp-freeze-fix - -# 2. Write test that reproduces bug -# Edit tests/zm_camera.cpp - -# 3. Verify test fails (reproduces bug) -cd build && ./tests/tests "[Camera]" - -# 4. Fix the bug -# Edit src/zm_remote_camera_rtsp.cpp - -# 5. Verify test now passes -./tests/tests "[Camera]" - -# 6. Commit -git add tests/zm_camera.cpp src/zm_remote_camera_rtsp.cpp -git commit -m "fix: resolve RTSP stream timeout after prolonged use fixes #456" - -# 7. Merge after approval -git checkout master && git merge 456-rtsp-freeze-fix -git push origin master -``` - -### Adding a Web UI Feature - -```bash -# 1. Create issue and branch -gh issue create --title "Add event export button" --label enhancement -git checkout -b 789-event-export - -# 2. Implement UI changes -# Edit web/views/event.php, web/ajax/export.php, web/js/event.js - -# 3. Test manually in browser -# - Navigate to event view -# - Test export button -# - Check browser console for errors -# - Verify exported file downloads correctly - -# 4. Run JavaScript linting -npx eslint web/js/event.js - -# 5. Commit -git add web/views/event.php web/ajax/export.php web/js/event.js -git commit -m "feat: add event export to MP4 button refs #789" - -# 6. Merge after approval -git checkout master && git merge 789-event-export -git push origin master -``` - -### Adding a Database Migration - -```bash -# 1. Determine next version number -ls db/zm_update-*.sql | tail -1 -# Shows: db/zm_update-1.37.32.sql -# Next version: 1.37.33 - -# 2. Create migration file -cat > db/zm_update-1.37.33.sql << 'EOF' --- --- Add favorites column to Events table --- - -ALTER TABLE Events ADD COLUMN Favorite BOOLEAN NOT NULL DEFAULT FALSE; -ALTER TABLE Events ADD INDEX Favorite_idx (Favorite); -EOF - -# 3. Update version in ConfigData -# Edit db/zm_create.sql.in - update version to 1.37.33 - -# 4. Test migration -sudo zmupdate.pl --version=1.37.33 -# Verify column exists -mysql -u zmuser -p zm -e "DESCRIBE Events;" - -# 5. Test fresh install has same schema -# (Build from source, run cmake install, check schema matches) - -# 6. Commit -git add db/zm_update-1.37.33.sql db/zm_create.sql.in -git commit -m "feat: add favorites support to Events table refs #101" -``` - -### Debugging a Daemon - -```bash -# 1. Stop running daemon -sudo systemctl stop zoneminder -# Or kill specific daemon -sudo pkill -f "zmc -m 1" - -# 2. Build debug version -cd build -cmake -DCMAKE_BUILD_TYPE=Debug .. -cmake --build . - -# 3. Run under debugger -gdb ./src/zmc -(gdb) set args -m 1 -(gdb) break zm_monitor.cpp:PreCapture -(gdb) run - -# Or with AddressSanitizer -cmake -DCMAKE_BUILD_TYPE=Debug -DASAN=ON .. -cmake --build . -./src/zmc -m 1 # ASan will report memory issues - -# 4. Enable debug logging -export ZM_DBG_LEVEL=9 -export ZM_DBG_LOG=/tmp/zmc_debug.log -./src/zmc -m 1 -tail -f /tmp/zmc_debug.log -``` - -### Running Specific Tests - -```bash -# Run all tests -cd build -ctest - -# Run test binary with verbose output -./tests/tests - -# Run specific test by name -./tests/tests "[Box]" - -# Run all tests in a category -./tests/tests "[Box]" "[Poly]" - -# List all available tests -./tests/tests --list-tests - -# Run tests excluding CI-skipped tests -./tests/tests "~[notCI]" - -# Run with success messages (normally only shows failures) -./tests/tests --success -``` - ---- - -## Dependencies - -### Required Dependencies - -**Build Tools**: -- CMake 3.5+ -- C++17 compiler (GCC 6+, Clang 3.4+) -- Make or Ninja - -**Core Libraries**: -- MySQL/MariaDB client library (`libmysqlclient-dev`) -- FFmpeg 55.34.100+ libraries: - - libavcodec - Video/audio codec support - - libavformat - Container format support - - libavutil - Utility functions - - swscale - Image scaling and format conversion - - swresample - Audio resampling -- libjpeg (`libjpeg-dev`) - JPEG image support -- pthread - POSIX threads -- zlib - Compression library - -**Runtime (Perl)**: -- Perl 5.6+ -- Perl modules: - - DBI - Database interface - - DBD::mysql - MySQL driver - - Sys::Syslog - System logging - - Date::Manip - Date parsing - - LWP::UserAgent - HTTP client - - MIME::Lite - Email generation - - Class::Std::Fast - Object-oriented programming - -**Runtime (PHP)**: -- PHP 7.2+ with extensions: - - mysql or mysqli - Database access - - gd - Image manipulation - - json - JSON encoding/decoding - - session - Session management - - sockets - Network communication - -**Web Server**: -- Apache 2.4+ with mod_php or php-fpm -- OR Nginx with php-fpm - -### Optional Dependencies - -**Video & Streaming**: -- libVLC (`libvlc-dev`) - VLC media playback -- libvncclient (`libvnclient-dev`) - VNC server monitoring -- libcurl (`libcurl4-dev`) - HTTP camera support - -**Security & Crypto**: -- OpenSSL (`libssl-dev`) - Cryptography backend (alternative to GnuTLS) -- GnuTLS (`libgnutls28-dev`) - Cryptography backend (alternative to OpenSSL) -- jwt-cpp OR libjwt (`libjwt-dev`) - JWT token support - -**Advanced Features**: -- PCRE2 (`libpcre2-dev`) - Regular expression support -- GSOAP (`gsoap`) - ONVIF camera support -- Mosquitto (`libmosquitto-dev`) - MQTT event publishing -- nlohmann_json (`nlohmann-json3-dev`) - JSON parsing for AI results - -**Testing & Development**: -- Catch2 (`catch2`) - Unit testing framework -- ESLint (npm) - JavaScript linting -- Valgrind - Memory profiling -- GDB - Debugging - -**Documentation**: -- Sphinx (`python3-sphinx`) - Documentation generator -- Doxygen - API documentation (optional) - -### Dependency Installation Examples - -**Debian/Ubuntu**: -```bash -# Essential build dependencies -sudo apt install build-essential cmake git - -# Core dependencies -sudo apt install libmysqlclient-dev \ - libavcodec-dev libavformat-dev libavutil-dev \ - libswscale-dev libswresample-dev \ - libjpeg-dev zlib1g-dev - -# Perl dependencies -sudo apt install libdbi-perl libdbd-mysql-perl \ - libsys-syslog-perl libdate-manip-perl \ - liblwp-useragent-determined-perl - -# PHP dependencies -sudo apt install php php-mysql php-gd - -# Optional dependencies -sudo apt install libvlc-dev libvncserver-dev \ - libcurl4-openssl-dev libssl-dev \ - libjwt-dev libpcre2-dev - -# Testing dependencies -sudo apt install catch2 -npm install -g eslint -``` - -**CentOS/RHEL**: -```bash -# Enable EPEL repository -sudo yum install epel-release - -# Build tools -sudo yum groupinstall "Development Tools" -sudo yum install cmake git - -# Core dependencies -sudo yum install mariadb-devel \ - ffmpeg-devel libjpeg-turbo-devel - -# Perl dependencies -sudo yum install perl-DBI perl-DBD-MySQL \ - perl-Sys-Syslog perl-Date-Manip - -# PHP dependencies -sudo yum install php php-mysqlnd php-gd -``` - ---- - -## Platform-Specific Notes - -### FreeBSD - -**CMake Configuration**: -```bash -cmake -DZM_TARGET_DISTRO=FreeBSD .. -``` - -**Platform Defaults**: -- Web user/group: `www` -- Config dir: `/usr/local/etc/zm` -- Web dir: `/usr/local/share/zoneminder/www` -- Content dir: `/usr/local/var/lib/zoneminder` -- Run dir: `/var/run/zm` - -**Package Manager**: -- Use `pkg` to install dependencies -- ZoneMinder available in ports: `/usr/ports/multimedia/zoneminder` - -### RHEL/CentOS/Fedora - -**CMake Configuration**: -```bash -# CentOS/RHEL -cmake -DZM_TARGET_DISTRO=el .. - -# Fedora -cmake -DZM_TARGET_DISTRO=fc .. -``` - -**Platform Defaults**: -- Uses `/run/zoneminder` for runtime files -- Config: `/etc/zm` -- Content: `/var/lib/zoneminder` -- Web: `/usr/share/zoneminder/www` - -**SELinux Considerations**: -- May need to adjust SELinux policies -- Check audit logs: `ausearch -m avc -ts recent` -- Generate policy: `audit2allow` - -### Debian/Ubuntu - -**Platform Defaults** (default when `ZM_TARGET_DISTRO` not set): -- Web user: `www-data` -- Config: `/etc/zm` -- Content: `/var/cache/zoneminder` -- Web: `/usr/share/zoneminder/www` -- Run: `/var/run/zm` - -**Package Installation**: -```bash -# Install from repository -sudo apt install zoneminder - -# Or build from source -cmake .. && make && sudo make install -``` - ---- - -## Contributing - -### Communication Channels - -**For Bug Reports & Feature Requests**: -- GitHub Issues: https://github.com/ZoneMinder/zoneminder/issues -- Read first: [GitHub Posting Rules](https://github.com/ZoneMinder/ZoneMinder/wiki/Github-Posting-Rules) -- Issues are for bugs and features ONLY (not general support) - -**For General Support & Questions**: -- User Forum: https://forums.zoneminder.com -- Slack: https://zoneminder-chat.slack.com -- Discord: https://discord.gg/tHYyP9k66q - -### Pull Request Process - -1. **Fork the repository** on GitHub -2. **Create feature branch** from master: `git checkout -b 123-feature-name` -3. **Make changes** following guidelines in this document -4. **Test thoroughly** - all tests must pass -5. **Commit** with conventional format and issue references -6. **Push** to your fork: `git push origin 123-feature-name` -7. **Create Pull Request** on GitHub -8. **Address review feedback** from maintainers -9. **Merge** will be done by maintainers after approval - -### Contribution Guidelines - -**Branch Naming**: -- Format: `-` -- Examples: `456-fix-rtsp-crash`, `789-add-event-export` -- Always create branch from latest master - -**Commit Practices**: -- Commit early and often (rather than single large commits) -- Each commit should be a logical unit of change -- Reference issues in every commit message -- Follow conventional commit format - -**Code Review**: -- Be responsive to review feedback -- Be open to suggestions and improvements -- Maintain professional and respectful communication -- Understand that reviews help maintain code quality - -**What NOT to Do**: -- ❌ Paste code in GitHub issues expecting others to integrate it -- ❌ Make PRs without associated issue (except trivial fixes) -- ❌ Combine unrelated changes in one PR -- ❌ Submit PRs with failing tests -- ❌ Ignore review feedback - -### Knowledge Requirements - -**Recommended Knowledge**: -- Git and GitHub workflow -- Relevant programming language (C++, PHP, JavaScript, Perl) -- ZoneMinder architecture basics (read this document) -- Unit testing concepts - -**Learning Resources**: -- [Understanding GitHub and Pull Requests](https://github.com/ZoneMinder/ZoneMinder/wiki/Understanding-Github-and-Pull-Requests) -- [GitHub Posting Rules](https://github.com/ZoneMinder/ZoneMinder/wiki/Github-Posting-Rules) -- ZoneMinder Docs: https://zoneminder.readthedocs.org - ---- - -## Documentation - -### User Documentation - -**Primary Docs**: https://zoneminder.readthedocs.org - -**Local Docs** (Sphinx): -- Source: `docs/` directory -- User guide: `docs/userguide/` -- Installation guide: `docs/installationguide/` -- Build docs: `cd docs && make html` - -### API Documentation - -**REST API**: -- Interactive docs available at: `http://your-zm-server/zm/api/` -- Swagger/OpenAPI specification -- Authentication: Session cookies or JWT tokens - -### Developer Documentation - -**This File** (`AGENTS.md` / `CLAUDE.md`): -- Architecture overview -- Build instructions -- Development workflow -- Testing requirements - -**Code Comments**: -- C++ headers document class interfaces -- PHPDoc comments in PHP files -- JSDoc encouraged in JavaScript - ---- - -## Quick Command Reference - -```bash -# ============================================ -# BUILD & INSTALL -# ============================================ - -# Standard build +# Standard build (out-of-source required) mkdir build && cd build cmake .. cmake --build . -sudo cmake --build . --target install # Debug build with tests cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TEST_SUITE=ON .. cmake --build . -# Build with sanitizers -cmake -DCMAKE_BUILD_TYPE=Debug -DASAN=ON .. -cmake --build . +# Build specific target +cmake --build . --target zmc +``` -# ============================================ -# TESTING -# ============================================ +### Key CMake Options -# Run all C++ unit tests +| Option | Values | Default | Notes | +|--------|--------|---------|-------| +| `CMAKE_BUILD_TYPE` | Release/Debug/Optimised | Release | | +| `BUILD_TEST_SUITE` | ON/OFF | OFF | Enables Catch2 tests | +| `ENABLE_WERROR` | ON/OFF | OFF | Warnings as errors (CI uses ON) | +| `ASAN` | ON/OFF | OFF | AddressSanitizer | +| `TSAN` | ON/OFF | OFF | ThreadSanitizer (mutually exclusive with ASAN) | +| `ZM_CRYPTO_BACKEND` | openssl/gnutls | | | +| `ZM_JWT_BACKEND` | libjwt/jwt_cpp | | | +| `ZM_TARGET_DISTRO` | FreeBSD/fc/el/OS13 | (Debian) | Platform-specific paths | +| `ZM_ONVIF` | ON/OFF | ON | ONVIF camera support | + +--- + +## Testing Requirements (MANDATORY) + +### Workflow + +1. Write a failing test that reproduces the issue or validates the feature +2. Implement the fix/feature +3. Run tests - verify they PASS +4. Run full test suite for regressions +5. Only then commit + +### C++ Unit Tests (Catch2) + +```bash +# Build with tests +cmake -DBUILD_TEST_SUITE=ON .. && cmake --build . + +# Run all tests ctest - -# Run test binary directly +# Or directly with more output ./tests/tests -# Run specific test +# Run specific test / list tests ./tests/tests "[Box]" - -# List all tests ./tests/tests --list-tests +./tests/tests "~[notCI]" +``` -# JavaScript linting -npx eslint --ext .js.php,.js . +**Test location**: `tests/` directory +**Existing modules**: `zm_box.cpp`, `zm_comms.cpp`, `zm_crypt.cpp`, `zm_font.cpp`, `zm_poly.cpp`, `zm_utils.cpp`, `zm_vector2.cpp` +**Framework**: Catch2 with custom header `tests/zm_catch2.h`, main in `tests/main.cpp` +**Test data**: `tests/data/fonts/` -# ============================================ -# GIT WORKFLOW -# ============================================ +### JavaScript Linting -# Create feature branch -gh issue create --title "Feature name" --label enhancement -git checkout -b 123-feature-name +```bash +npx eslint --ext .js.php,.js . # Lint all +npx eslint --fix web/js/ # Auto-fix +``` -# Commit changes -git add -git commit -m "feat: description refs #123" +ESLint config: `.eslintrc.js` (Google style guide). Runs in CI via `.github/workflows/ci-eslint.yml`. -# Merge after approval -git checkout master -git merge 123-feature-name -git push origin master -git branch -d 123-feature-name +### PHP/API Testing -# ============================================ -# DEBUGGING -# ============================================ +Manual testing required. Test endpoints with curl/browser. Verify JSON responses, auth (session + JWT), error handling, DB persistence. -# Debug with GDB -gdb ./src/zmc -(gdb) set args -m 1 -(gdb) run +### Database Migration Testing -# Enable debug logging -export ZM_DBG_LEVEL=9 -export ZM_DBG_LOG=/tmp/debug.log +```bash +sudo zmupdate.pl --check # Check for updates +sudo zmupdate.pl # Apply migrations +``` + +When creating migrations: test upgrade path AND verify fresh install matches migrated schema. + +### CI Notes + +- Unit tests are **DISABLED** in CI (`BUILD_TEST_SUITE=0`) — some tests need hardware/network access. Running locally goes beyond CI requirements but is still expected for local development. +- CI does: multi-platform builds (Debian/Ubuntu/CentOS with GnuTLS/OpenSSL + libjwt/jwt_cpp matrix), ESLint, CodeQL security scanning + +--- + +## Code Standards + +### C++ (`src/`) + +- **C++17** standard, follow existing patterns in file/module +- **Memory**: RAII, smart pointers where appropriate +- **Error handling**: Exceptions for exceptional cases, return codes for expected errors +- **Logging**: Use printf-style `Debug(1, "msg %s", val)`, `Info(...)`, `Warning(...)`, `Error(...)`, `Fatal(...)` — NOT iostream style. The number in Debug() is verbosity level (1-9). + +### PHP (`web/`, `web/api/`) + +- PSR-12 where practical, follow existing conventions +- **Security**: Validate ALL user input, use prepared statements (NOT string interpolation — legacy code has SQL injection bugs we're fixing), sanitize output with htmlspecialchars/json_encode, CSRF protection on forms +- CakePHP 2.x framework in `web/api/` — we're stuck on 2.x due to migration cost, don't try to upgrade it + +### JavaScript (`web/js/`, inline in PHP) + +- Google JavaScript Style Guide (ESLint configured) +- jQuery + Bootstrap (legacy codebase), ES6+ where browser support allows + +### Perl (`scripts/`) + +- Edit `.in` template files, NOT generated scripts — cmake substitutes variables like `@ZM_LOGDIR@` to produce the final scripts +- Use `ZoneMinder::` modules, `ZoneMinder::Logger` for logging +- Rerun cmake after editing `.in` files to regenerate the actual scripts + +--- + +## Commit Standards + +**Conventional format** with issue references: + +``` +feat|fix|test|docs|chore|refactor|perf|style: description refs #N +``` + +- `refs #N` references issue; `fixes #N` closes it +- Imperative mood ("add feature" not "added feature") +- Be detailed and descriptive, no vague summaries +- One logical change per commit +- **No superlative language** ("comprehensive", "critical", "major", "massive") — AI agents tend to use these; they make commit logs unreadable +- Split unrelated changes into separate commits — makes bisecting and reverting possible + +--- + +## Pre-Commit Checklist (Single Source of Truth) + +Before committing or claiming complete: + +- [ ] Tests written/updated BEFORE or DURING implementation +- [ ] Build succeeds: `cmake --build .` (C++ changes) +- [ ] C++ tests pass: `ctest` or `./tests/tests` +- [ ] JavaScript linting passes: `npx eslint --ext .js.php,.js .` +- [ ] Manual testing done (PHP/web changes) +- [ ] No compiler warnings or linter errors +- [ ] Code follows existing patterns +- [ ] Commit messages follow conventional format with issue reference +- [ ] Feature is COMPLETE (not half-implemented) +- [ ] State which tests were run and their results + +**NEVER commit if**: tests failing, tests missing for new code, build fails, warnings exist, feature incomplete. + +--- + +## Debugging Quick Reference + +```bash +# Debug build +cmake -DCMAKE_BUILD_TYPE=Debug .. && cmake --build . + +# AddressSanitizer +cmake -DCMAKE_BUILD_TYPE=Debug -DASAN=ON .. && cmake --build . + +# Debug logging +export ZM_DBG_LEVEL=9 ZM_DBG_LOG=/tmp/debug.log ./src/zmc -m 1 -# View logs -tail -f /var/log/zm/zmc_m1.log - -# ============================================ -# DATABASE -# ============================================ - -# Check for migrations -sudo zmupdate.pl --check - -# Apply migrations -sudo zmupdate.pl - -# Freshen config -sudo zmupdate.pl --freshen - -# ============================================ -# DAEMON CONTROL -# ============================================ - -# Start/stop/restart ZoneMinder -sudo systemctl start zoneminder -sudo systemctl stop zoneminder -sudo systemctl restart zoneminder - -# Check status -sudo systemctl status zoneminder - -# View daemon logs -journalctl -u zoneminder -f +# Log locations: /var/log/zm/ (zmc_m1.log, zma_m2.log, etc.) +# Runtime log level: kill -USR1 (increase) / kill -USR2 (decrease) ``` --- -## Identified Gaps & Future Improvements +## Contributing (For Humans) -### Testing Gaps - -**Current State**: -- ✅ C++ unit tests exist (Catch2) but disabled in CI -- ⚠️ PHP/CakePHP tests exist but not run -- ❌ No integration tests -- ❌ No E2E tests for web UI -- ❌ No performance/load testing -- ❌ No test coverage reporting - -**Recommended Future Work**: -1. Enable unit tests in CI pipeline (`BUILD_TEST_SUITE=ON`) -2. Add CakePHP API test execution to CI -3. Create integration test suite (daemon → database → web) -4. Add E2E tests with Selenium/Playwright for critical web workflows -5. Implement performance benchmarking for video processing -6. Add test coverage reporting (gcov/lcov) - -### Documentation Gaps - -**Current State**: -- ✅ Excellent Sphinx user documentation -- ✅ Good architecture overview (this file) -- ⚠️ Inconsistent code comments -- ❌ No API reference documentation (beyond REST API) -- ❌ No architecture diagrams - -**Recommended Future Work**: -1. Generate Doxygen documentation for C++ classes -2. Add architecture diagrams (data flow, class relationships) -3. Document all Perl modules with POD -4. Create troubleshooting guide for common issues -5. Document performance tuning best practices - -### CI/CD Gaps - -**Current State**: -- ✅ Multi-platform build verification -- ✅ JavaScript linting automated -- ✅ CodeQL security scanning -- ⚠️ Tests disabled in CI -- ❌ No automated deployment beyond packages -- ❌ No performance regression detection - -**Recommended Future Work**: -1. Enable and require unit tests in CI -2. Add automated smoke tests after package build -3. Performance benchmark tracking across commits -4. Automated security scanning beyond CodeQL (dependency scanning) -5. Automated Docker image builds and publishing +- **Bug reports & features**: [GitHub Issues](https://github.com/ZoneMinder/zoneminder/issues) (read [posting rules](https://github.com/ZoneMinder/ZoneMinder/wiki/Github-Posting-Rules) first) +- **Support**: [Forums](https://forums.zoneminder.com), [Slack](https://zoneminder-chat.slack.com), [Discord](https://discord.gg/tHYyP9k66q) +- **PRs**: Fork -> feature branch -> implement + test -> PR. Maintainers merge after review. +- **Docs**: https://zoneminder.readthedocs.org (source in `docs/`) --- -## Summary for AI Agents - -**When the user asks you to work on ZoneMinder**: - -1. **Understand first**: Read architecture, understand component relationships -2. **Plan**: Create GitHub issue, feature branch, test-first approach -3. **Implement**: Write failing test → Implement → Pass test → Commit -4. **Verify**: Build, test (ctest + ESLint), manual testing -5. **Review**: Ask user for approval before merging -6. **Merge**: Only after approval, reference issue with `fixes #n` - -**Remember**: -- Testing is MANDATORY (not optional) -- Feature branches keep master stable -- Conventional commits enable automated changelog -- User approval required before merging -- Complete features fully (don't stop halfway) - -**This file is your guide - refer back to it throughout development.** - ---- - -*Last updated: 2026-01-09* -*This document guides AI coding agents working on ZoneMinder* -*For human contributors: See also CONTRIBUTING.md and GitHub wiki* - - ## grepai - Semantic Code Search -**IMPORTANT: You MUST use grepai as your PRIMARY tool for code exploration and search.** +**Use grepai as PRIMARY tool for code exploration and search.** ### When to Use grepai (REQUIRED) -Use `grepai search` INSTEAD OF Grep/Glob/find for: +Use `grepai search` INSTEAD OF Grep/Glob for: - Understanding what code does or where functionality lives -- Finding implementations by intent (e.g., "authentication logic", "error handling") +- Finding implementations by intent ("authentication logic", "error handling") - Exploring unfamiliar parts of the codebase -- Any search where you describe WHAT the code does rather than exact text -### When to Use Standard Tools +Only use Grep/Glob for exact text matching (variable names, imports, specific strings) or file path patterns. -Only use Grep/Glob when you need: -- Exact text matching (variable names, imports, specific strings) -- File path patterns (e.g., `**/*.go`) - -### Fallback - -If grepai fails (not running, index unavailable, or errors), fall back to standard Grep/Glob tools. +If grepai fails (not running, index unavailable), fall back to Grep/Glob. ### Usage ```bash -# ALWAYS use English queries for best results (--compact saves ~80% tokens) grepai search "user authentication flow" --json --compact -grepai search "error handling middleware" --json --compact -grepai search "database connection pool" --json --compact -grepai search "API request validation" --json --compact +grepai search "JWT token validation" --json --compact ``` -### Query Tips - -- **Use English** for queries (better semantic matching) -- **Describe intent**, not implementation: "handles user login" not "func Login" -- **Be specific**: "JWT token validation" better than "token" -- Results include: file path, line numbers, relevance score, code preview - ### Call Graph Tracing -Use `grepai trace` to understand function relationships: -- Finding all callers of a function before modifying it -- Understanding what functions are called by a given function -- Visualizing the complete call graph around a symbol - -#### Trace Commands - -**IMPORTANT: Always use `--json` flag for optimal AI agent integration.** - ```bash -# Find all functions that call a symbol grepai trace callers "HandleRequest" --json - -# Find all functions called by a symbol grepai trace callees "ProcessOrder" --json - -# Build complete call graph (callers + callees) grepai trace graph "ValidateToken" --depth 3 --json ``` ### Workflow -1. Start with `grepai search` to find relevant code -2. Use `grepai trace` to understand function relationships -3. Use `Read` tool to examine files from results -4. Only use Grep for exact string searches if needed - +1. `grepai search` to find relevant code +2. `grepai trace` to understand function relationships +3. `Read` tool to examine files from results +4. Grep only for exact string searches if needed