# magendoo/module-customer-segment

> Magento 2 dynamic customer segmentation module — rule-based segments with admin UI, REST API, CLI, and Cart Price Rule integration.

`composer require magendoo/module-customer-segment`

Canonical URL: https://packagento.com/magendoo/module-customer-segment

## At a glance

- **Vendor**: magendoo (https://packagento.com/magendoo.md)
- **Latest version**: 2.0.0 — released 2026-07-20
- **Pricing**: Free
- **Package type**: Magento 2 module
- **Status**: active, accepting new buyers

## Installation

Packagento is licence-gated, so even free packages need a licence on a project before Composer can resolve them.

1. **Sign in or create an account** at https://packagento.com/customer/account/.

2. **Add the package to your account.** Open https://packagento.com/magendoo/module-customer-segment and complete the free checkout. A licence is minted automatically.

3. **Create or pick a project, then activate the licence on it.**
   - Projects represent the Magento installs you deploy to. Manage them at https://packagento.com/projects/.
   - Activate the new licence on the project you'll deploy this package to. Activation is what generates the Composer credentials scoped to that project.

4. **Add the project credentials to your Magento codebase.**

   Grab the project's public + private key from https://packagento.com/projects/ (open the project, then its Credentials tab), and add them to `auth.json`:

   ```json
   {
     "http-basic": {
       "packagento.com": {
         "username": "ppk_live_...",
         "password": "psk_live_..."
       }
     }
   }
   ```

   Add the Packagento Composer repository to `composer.json`:

   ```json
   {
     "repositories": [
       { "type": "composer", "url": "https://packagento.com" }
     ]
   }
   ```

5. **Install and apply.**

   ```bash
   composer require magendoo/module-customer-segment:*
   bin/magento setup:upgrade
   bin/magento setup:di:compile
   bin/magento cache:flush
   ```

## What it does

Magento 2 dynamic customer segmentation module — rule-based segments with admin UI, REST API, CLI, and Cart Price Rule integration.

## README

A comprehensive Customer Segmentation module for Magento 2 Community Edition that enables merchants to create dynamic customer segments based on various criteria including customer attributes, order history, shopping cart data, and behavior patterns.

### Screenshots

#### Segment Grid — manage all your customer segments at a glance

![Customer Segments Grid](docs/magento2-customer-segments-list.png)

#### Segment Editor — visual rule builder with conditions and customer matching

![Customer Segment Edit](docs/magento2-customer-segments-edit.png)

### Documentation

| Document | Description |
|----------|-------------|
| [User Guide](docs/USER_GUIDE.md) | End-user documentation for managing segments |
| [Developer Documentation](docs/DEVELOPER.md) | Technical documentation for developers |
| [API Documentation](docs/API_DOCUMENTATION.md) | REST API reference and examples |
| [Testing Guide](TESTING.md) | Unit testing patterns and best practices |
| [Changelog](CHANGELOG.md) | Version history and changes |

### Features

#### Customer Segmentation
- **Dynamic Segments**: Automatically assign customers based on rules
- **Manual Segments**: Static customer assignments
- **Real-time Updates**: Refresh segments on customer events
- **Scheduled Updates**: Cron-based segment refresh

#### Condition Types

##### Customer Attributes
- Email, First Name, Last Name
- Date of Birth, Gender
- Tax/VAT Number
- Website, Store View, Customer Group
- Account Creation Date

##### Order History
- Total Orders Count
- Total Revenue / Average Order Value
- First/Last Order Date
- Total Items Purchased
- Used Coupon Codes
- Payment/Shipping Methods
- Shipping Countries
- Order Status

##### Shopping Cart
- Cart Subtotal
- Cart Items Count
- Contains Products (by SKU)
- Has Active Cart
- Days Since Cart Activity

##### Product Interactions
- Purchased Products (SKU)
- Purchased from Categories
- Wishlist Items Count

> Viewed-categories (product-view) segmentation is on the [roadmap](CHANGELOG.md#roadmap-not-yet-implemented) and not yet available.

#### Admin Features
- Grid view of all segments with customer counts
- Create/Edit segments with visual rule builder
- Preview matching customers before saving
- "Matched Customers" tab on edit page shows assigned customers
- Refresh button on edit page
- Mass actions (Delete, Refresh)
- Export segment customers (CSV/XML)

#### API & Integrations
- REST API for segment management
- CLI commands for segment operations
- Integration with Cart Price Rules
- Segment indexer with mview support

### Installation

#### Via Composer (Recommended)

This package is not on Packagist yet, so register the repository first:

```bash
composer config repositories.magendoo-customer-segment vcs https://github.com/florinel-chis/magendoo-m2-customersegment
composer require magendoo/module-customer-segment
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
```

#### Manual Installation

1. Extract files to `app/code/Magendoo/CustomerSegment/`
2. Run the following commands:

```bash
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush
```

### Configuration

- **Segment grid** (create/edit/refresh segments): **Customers → Customer Segments**
- **Module settings** (enable/disable, default refresh mode, cron schedule):
  **Stores → Configuration → Customers → Customer Segments**

### Usage

#### Creating a Segment

1. Navigate to **Customers → Customer Segments**
2. Click **"Add New Segment"**
3. Fill in the general information:
   - Name (required)
   - Description (optional)
   - Status (Active/Inactive)
   - Refresh Mode (Manual/Cron/Real-time)
4. Configure conditions in the **Conditions** tab
5. Save the segment
6. Click **"Refresh Segment Data"** to populate customers

#### Segment Refresh Modes

| Mode | Description |
|------|-------------|
| **Manual** | Admin must click refresh button to update |
| **Cron** | Updated automatically on cron schedule (default: `*/5 * * * *`, every 5 minutes) |
| **Real-time** | Updated on customer events (register, save, login, order, quote merge) |

#### CLI Commands

```bash
## Refresh specific segment(s)
bin/magento magendoo:customer-segment:refresh 1
bin/magento magendoo:customer-segment:refresh 1 2 3

## Refresh all active segments
bin/magento magendoo:customer-segment:refresh --all

## Export segment customers
bin/magento magendoo:customer-segment:refresh 1 --export --format=csv
```

#### Using Segments in Cart Price Rules

1. Go to **Marketing → Cart Price Rules**
2. Create or edit a rule
3. In the **Conditions** section, add condition:
   - **Customer Segment** → **is** → *[Select your segment]*
4. Save the rule

### API Reference

#### REST API Endpoints

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/V1/customer-segments` | List all segments |
| GET | `/V1/customer-segments/:segmentId` | Get segment by ID |
| POST | `/V1/customer-segments` | Create new segment |
| PUT | `/V1/customer-segments/:segmentId` | Update segment (partial updates merge onto the stored record) |
| DELETE | `/V1/customer-segments/:segmentId` | Delete segment |
| POST | `/V1/customer-segments/:segmentId/refresh` | Refresh a single segment; returns the assigned count |
| POST | `/V1/customer-segments/refresh-all` | Refresh all active segments |
| GET | `/V1/customers/:customerId/segments` | Get the customer's segments |
| GET | `/V1/customers/:customerId/segment-ids` | Get the customer's segment IDs |
| GET | `/V1/customers/:customerId/segments/:segmentId/check` | Check if a customer is in a segment |
| GET | `/V1/customer-segments/:segmentId/customers?format=csv\|xml` | Export a segment's customers; `format` is required and returns a CSV or XML string |

#### Example: Create Segment via API

_(README truncated for .md surface. Full README on https://packagento.com/magendoo/module-customer-segment.)_

## Changelog

All notable changes to the Magendoo CustomerSegment module will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### [2.0.0] - 2026-07-20

A correctness-focused release that fixes the segmentation engine along its main axis. Several fixes
change stored data and behaviour, so this is a breaking release.

> **Upgrade step (required):** run `bin/magento setup:upgrade`. It applies two patches:
> a schema patch that removes stale duplicate indexes/foreign keys left by older installs, and a
> data patch that rewrites any segment whose conditions were stored in the legacy numeric-key shape
> into the canonical `conditions` tree. Re-run refresh on affected segments afterwards.

#### Fixed
- **CRITICAL**: Admin-created segments ignored their conditions and matched every customer. Condition
  children were serialized under numeric position keys with no `conditions` key, so the rule tree
  loaded as an empty combine. Conditions now serialize under an ordered `conditions` list that
  round-trips through Magento's rule engine. Existing broken rows are migrated by `setup:upgrade`.
- **CRITICAL**: Whole condition families matched nobody or inverted their meaning — order
  payment/status/coupon/country, product purchased-negation and purchased-categories, cart subtotal
  `>`/`<`, and cart/negation operators. These now evaluate correctly, with negation applied at the
  customer level and explicit zero-row (no orders / empty cart) handling.
- **CRITICAL**: Partial REST updates (`PUT`) overwrote stored scalars with defaulted DTO values,
  resetting `customer_count`, `is_active`, `refresh_mode`, and wiping `conditions_serialized`.
  Updates now merge onto the loaded model.
- **MAJOR**: Membership matching was O(customers x conditions), issuing one query per customer per
  leaf. Conditions that can express themselves as a single query now resolve set-based.
- **MAJOR**: `refresh <id> --export` always crashed under `strict_types`; the CLI now casts the id
  and handles export correctly.
- **MAJOR**: CSV export crashed on PHP 8.4 (`fputcsv` deprecation). Fixed, and export now neutralizes
  leading formula characters to prevent spreadsheet formula injection.
- **MAJOR**: MView customer subscription refreshed the wrong segment (customer ids were treated as
  segment ids). The changelog/indexer wiring is now segment-scoped and no longer self-perpetuates.
- **MEDIUM**: Staleness checks compared stored UTC timestamps against session-timezone `NOW()`;
  comparisons are now UTC-consistent (`UTC_TIMESTAMP()` / UTC-aware parsing).
- **MEDIUM**: Segment refresh is now atomic (remove-all + mass-assign wrapped in one transaction).

#### Added
- `Helper\Data::isEnabled()` now actually gates the module: realtime observers, the cron dispatcher,
  and the CLI no-op when `customersegment/general/enabled` is off.
- `SegmentManagementInterface::updateCustomerMembership(int $customerId)` — re-evaluates a single
  customer against active realtime segments (no full rescan). Realtime observers call only this.
- Activity log is now live: `magendoo_customer_segment_log` receives real rows on save and refresh
  (`Model\ResourceModel\Log::log()`).
- `Setup\Patch\Schema\DropLegacyDuplicateIndexes` and `Setup\Patch\Data\MigrateConditionsSerialized`.

#### Changed
- **Behavior:** a segment with no conditions now matches **no** customers. Previously an empty (or
  admin-saved-but-broken) condition tree silently matched every customer. Define at least one
  condition to select customers.
- License is MIT across the module (`composer.json`, headers, `LICENSE`).
- `db_schema_whitelist.json` regenerated to match the explicit referenceIds in `db_schema.xml`
  (fixes duplicate indexes and foreign keys on clean installs).
- System config `enabled` is now a global (default-scope-only) operational toggle.
- Test suite migrated to PHPUnit 12 attributes.

_(Changelog truncated for .md surface. Full history on https://packagento.com/magendoo/module-customer-segment.)_

## Recent Versions

| Version | Released |
|---|---|
| 2.0.0 | 2026-07-20 |
| 1.1.0 | 2026-04-13 |

## Dependencies

### Require

| Package | Constraint |
|---|---|
| magento/framework | >=103.0.0 |
| magento/module-backend | >=102.0.0 |
| magento/module-catalog | >=104.0.0 |
| magento/module-customer | >=103.0.0 |
| magento/module-quote | >=101.2.0 |
| magento/module-rule | >=100.4.0 |
| magento/module-sales | >=103.0.0 |
| magento/module-ui | >=101.2.0 |
| php | >=8.1 |

### Require (dev)

| Package | Constraint |
|---|---|
| phpstan/phpstan | ^1.10 \|\| ^2.0 |
| phpunit/phpunit | ^10.5 |

## Quality

Latest release (2.0.0) fails the Packagento QA pipeline. Verdicts below are per-cell (Magento line × PHP version) for the matrixed tools, and run-once for the static / security tiers.


### Compatibility

Each Magento line is installed on its supported PHP versions, then the module is built (DI compile + static-content deploy). Cells show passed / failed / untested; staircase gaps render as `–`.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | Pass | Pass | – | – |
| 2.4.8 | – | Pass | Pass | – |
| 2.4.9 | – | – | Pass | Pass |


### Code Quality

Advisory checks against the module's source. Never affect the Compatibility verdict — a phpcs finding can't make a module incompatible.

#### Static Analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Warning | 55 | 55 warnings (ruleset: Magento2), 20 auto-fixable with phpcbf |
| PHPMD | Warning | 129 | 129 rule violations (UnusedPrivateField:129) |
| Cpd | Warning | 1 | 1 duplicated chunk spanning 54 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Info | 9 | valid; 9 advisory notes (composer validate --strict) |

#### PHPStan

Type-checks the module against a real Magento install. Re-runs per Magento + PHP version because resolvable symbols differ between releases.

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 35 | 35 | – | – |
| 2.4.8 | – | 35 | 35 | – |
| 2.4.9 | – | – | 35 | 35 |


### Tests

Unit and integration suites run per Magento + PHP cell. Test failures speak to the module's behaviour, not its compatibility with a line, so they're reported here separately.

#### Unit Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | 1 | 1 | – | – |
| 2.4.8 | – | 2 | 2 | – |
| 2.4.9 | – | – | Pass | 23 |

#### Integration Tests

| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | – | – |
| 2.4.8 | – | N/A | N/A | – |
| 2.4.9 | – | – | N/A | N/A |


### Security

Dependency-advisory audit (composer audit) plus a source malware scan. A malware detection fails the version outright.

| Tool | Status | Findings | Summary |
|---|---|---|---|
| Composer audit | Pass | 0 |  |
| Malware scan | Pass | 0 |  |

## Licence and pricing

Free. A licence is still minted on checkout and bound to your project for Composer access — no payment step.

Refundable within 14 days of first purchase via https://packagento.com/account/refunds/.

## Install via Claude Code or any MCP client

The Packagento MCP server can run the licence + project + Composer steps above in one tool call:

```
purchase_and_install_packages(
  composer_names=["magendoo/module-customer-segment"],
  project_id="proj_xxx"
)
```

This handles cart, checkout, licence minting, project activation, and writes auth.json credentials. Connect a client with `claude mcp add packagento https://mcp.packagento.com`. Full setup at https://packagento.com/docs/mcp-setup.

## Vendor

magendoo is a Magento 2 vendor on Packagento. See https://packagento.com/magendoo.md for their full catalogue.

