Skip to content

Plus / Audience Management REST

Flow ID: AD-46 | Module(s): Plus (domain layer) | Complexity: Medium Last Updated: 2026-04-04

Business Context

The Plus module provides customer audience segmentation through a modern REST API. Audiences are named segments of customers defined by tag-based criteria. Each audience can contain multiple criteria rules that reference customer tags and tag groups, with a configurable matching logic (AND/OR).

Audiences are used by the marketing system for targeted campaigns, email lists, and personalized promotions. The criteria system allows building dynamic audience definitions like "customers tagged with 'VIP' AND 'Athens'" or "customers tagged with 'Newsletter' OR 'Active buyer'".

The audience-to-customer relationship is maintained via a many-to-many junction table (shop_customer_audience), populated by the AddCustomersToAudience scheduled job based on the audience's criteria.


API Reference

REST Endpoints -- Audience

MethodPathActionDescription
GET/rest/plus/audienceindexList audiences (paginated)
GET/rest/plus/audience/itemitemGet single audience by filter
GET/rest/plus/audience/{id}showGet audience by ID
POST/rest/plus/audiencestoreCreate an audience
POST/rest/plus/audience/{id}updateUpdate an audience
DELETE/rest/plus/audience/{id}destroyDelete an audience

Filters: id (exact), name (partial), criteriaType (exact) Sorts: id, name, creationDatetimeRelations: criteria (one_to_many), customers (many_to_many)

REST Endpoints -- AudienceCriteria

MethodPathActionDescription
GET/rest/plus/audience-criteriaindexList criteria entries (paginated)
GET/rest/plus/audience-criteria/itemitemGet single criteria by filter
GET/rest/plus/audience-criteria/{id}showGet criteria by ID
POST/rest/plus/audience-criteriastoreCreate a criteria entry
POST/rest/plus/audience-criteria/{id}updateUpdate a criteria entry
DELETE/rest/plus/audience-criteria/{id}destroyDelete a criteria entry

Filters: id (exact), audienceId (exact), tagId (exact), groupId (exact) Sorts: id, audienceIdRelations: audience (belongs_to)

Legacy Admin Routes

No dedicated legacy admin routes for audience REST management. The legacy audience admin is in ecommercen/audience/controllers/Adv_audience_admin.php but manages audiences through a different interface.


Code Flow

Creating an Audience with Criteria

  1. POST /rest/plus/audience with:

    json
    {
      "name": "VIP Athens Customers",
      "criteriaType": 2,
      "creationDatetime": "2026-04-04T10:00:00"
    }
  2. Controllers\Audience::store() -> doStore() -> WriteService::create().

  3. WriteData::fromArray() maps input to name, criteria_type, creation_datetime, etc.

  4. Validator::validateForCreate() runs (currently stub).

  5. WriteRepository::insert() inserts into plus_audience.

  6. Returns the created audience via Resource.

  7. POST /rest/plus/audience-criteria for each criteria rule:

    json
    {
      "audienceId": 1,
      "tagId": 42,
      "groupId": 5,
      "customValue": null
    }
  8. Controllers\AudienceCriteria::store() inserts into plus_audience_criteria.

Querying an Audience with Nested Data

  1. GET /rest/plus/audience/1?with=criteria,customers
  2. Controllers\Audience::show(1) delegates to service.
  3. Service::get(1, ['criteria', 'customers']) fetches the audience and loads relations:
    • criteria: ONE_TO_MANY from plus_audience_criteria via audience_id
    • customers: MANY_TO_MANY from shop_customer via shop_customer_audience junction table
  4. Resource returns:
    json
    {
      "id": 1,
      "name": "VIP Athens Customers",
      "criteriaType": 2,
      "creationDatetime": "2026-04-04T10:00:00",
      "updateDatetime": null,
      "userId": 1,
      "criteria": [...],
      "customers": [...]
    }

Domain Layer

Audience (src/Domains/Plus/Audience/)

ComponentClassDescription
EntityRepository\Entityid, name, criteria_type, creation_datetime, update_datetime, user_id
RepositoryRepository\RepositoryTable plus_audience
RepositoryConfiguratorRepository\RepositoryConfiguratorcriteria -> AudienceCriteriaRepository (ONE_TO_MANY on audience_id), customers -> CustomerRepository (MANY_TO_MANY via shop_customer_audience)
ServiceServiceRead service with filter/sort/pagination
WriteServiceWriteServiceFull CRUD
WriteDataWriteDataname, criteriaType, creationDatetime, updateDatetime, userId
ValidatorValidatorStub validator
WriteRepositoryRepository\WriteRepositoryInsert/update/delete

AudienceCriteria (src/Domains/Plus/AudienceCriteria/)

ComponentClassDescription
EntityRepository\Entityid, audience_id, tag_id, group_id, custom_value
RepositoryRepository\RepositoryTable plus_audience_criteria
RepositoryConfiguratorRepository\RepositoryConfiguratoraudience -> AudienceRepository (BELONGS_TO on audience_id)
ServiceServiceRead service
WriteServiceWriteServiceFull CRUD
WriteDataWriteDataaudienceId, tagId, groupId, customValue
ValidatorValidatorStub validator

REST Layer (src/Rest/Plus/)

ComponentClassDescription
ControllerControllers\AudienceFull CRUD with HandlesWriteActions
ControllerControllers\AudienceCriteriaFull CRUD with HandlesWriteActions
ResourceResources\Audience\ResourceIncludes criteria (collection) and customers (collection) relations
ResourceResources\AudienceCriteria\ResourceIncludes audience (resource) relation
CollectionResources\Audience\CollectionPaginated audience list
CollectionResources\AudienceCriteria\CollectionPaginated criteria list
DI Containercontainer.phpREST controller registrations

DI Container (src/Domains/Plus/container.php)

Registers all Audience and AudienceCriteria domain services, repositories, write services, validators, and write repositories.


Architecture

ComponentPathPurpose
Domain containersrc/Domains/Plus/container.phpDI registration for all Plus domain services
REST containersrc/Rest/Plus/container.phpDI registration for REST controllers
REST routesapplication/config/rest_routes.php:1073-1102Audience and AudienceCriteria routes
Legacy audience adminecommercen/audience/controllers/Adv_audience_admin.phpLegacy admin UI (separate from REST)
Job: populate audiencesecommercen/job/libraries/AdvAddCustomersToAudience.phpScheduled job to evaluate criteria and populate shop_customer_audience

Data Model

plus_audience

ColumnTypeDescription
idint (PK)Auto-increment primary key
namevarcharAudience segment name
criteria_typeint (nullable)Criteria matching logic: null=ALL, 1=OR, 2=AND
creation_datetimedatetimeWhen the audience was created
update_datetimedatetime (nullable)When the audience was last updated
user_idint (nullable)Admin user who created the audience

plus_audience_criteria

ColumnTypeDescription
idint (PK)Auto-increment primary key
audience_idint (FK)Parent audience ID
tag_idint (FK)Customer tag ID for matching
group_idint (FK)Tag group ID for categorization
custom_valuevarchar (nullable)Optional custom matching value

shop_customer_audience (Junction Table)

ColumnTypeDescription
audience_idint (FK)Audience ID
customer_idint (FK)Customer ID

Configuration

No registry keys specific to audience REST. The personalization job queue must be enabled in application/config/jobs.php for the AddCustomersToAudience job to run.

SourceKeyDescription
Job configjobs.personalization.enabledMust be true for audience population jobs
Job configAddCustomersToAudienceSchedule 30 3 * * * (daily at 03:30)

Client Extension Points

  • Override RepositoryConfigurator: Add custom relations (e.g., to custom tag systems).
  • Override WriteService: Add custom validation or post-save hooks (e.g., trigger immediate audience population after criteria change).
  • Override Resource: Add computed fields to the API response (e.g., customer count).
  • Custom criteria evaluation: Override AddCustomersToAudience job to add custom matching logic beyond tag-based criteria.

Business Rules

  1. Criteria type semantics: null = match all criteria, 1 = OR logic (match any), 2 = AND logic (match all).
  2. Deferred population: The shop_customer_audience junction table is populated by the AddCustomersToAudience scheduled job, not in real-time when criteria are created.
  3. Tag-based criteria: Each criteria entry references a tag_id and group_id from the customer tagging system.
  4. Custom value: The custom_value field allows criteria with custom matching logic beyond simple tag presence.
  5. Many-to-many customers: The audience-customer relationship is a many-to-many -- a customer can belong to multiple audiences.