@reachy/audience-module 1.0.18 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +134 -0
- package/dist/AudienceModule.d.ts.map +1 -1
- package/dist/AudienceModule.js +1 -0
- package/dist/AudienceModule.js.map +1 -1
- package/dist/engine/V2AudienceEngine.d.ts +5 -0
- package/dist/engine/V2AudienceEngine.d.ts.map +1 -1
- package/dist/engine/V2AudienceEngine.js +210 -72
- package/dist/engine/V2AudienceEngine.js.map +1 -1
- package/dist/executors/ClickHouseEventQueryExecutor.d.ts +23 -0
- package/dist/executors/ClickHouseEventQueryExecutor.d.ts.map +1 -0
- package/dist/executors/ClickHouseEventQueryExecutor.js +803 -0
- package/dist/executors/ClickHouseEventQueryExecutor.js.map +1 -0
- package/dist/repositories/SupabaseContactRepository.d.ts +1 -0
- package/dist/repositories/SupabaseContactRepository.d.ts.map +1 -1
- package/dist/repositories/SupabaseContactRepository.js +1 -0
- package/dist/repositories/SupabaseContactRepository.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/AudienceModule.ts +1 -0
- package/src/engine/V2AudienceEngine.ts +240 -85
- package/src/executors/ClickHouseEventQueryExecutor.ts +853 -0
- package/src/repositories/SupabaseContactRepository.ts +2 -1
- package/src/types/index.ts +6 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Build & Development
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run build # Compile TypeScript → dist/
|
|
9
|
+
npm run watch # Compile with --watch for dev
|
|
10
|
+
npm run clean # Remove dist/
|
|
11
|
+
npx tsc --noEmit # Type-check without emitting
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
No test framework or linter is configured. CI is GitLab (`.gitlab-ci.yml`): lint_and_test → build → tag → publish_npm (manual).
|
|
15
|
+
|
|
16
|
+
Published as `@reachy/audience-module` on npm (v1.0.19). Peer dependency: `@supabase/supabase-js ^2.x`.
|
|
17
|
+
|
|
18
|
+
## Architecture
|
|
19
|
+
|
|
20
|
+
Standalone npm package that evaluates audience segmentation criteria against contacts and events. Consumed by `reachy-api` and other Reachy services.
|
|
21
|
+
|
|
22
|
+
### Execution flow
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
AudienceModule (facade)
|
|
26
|
+
→ CriteriaParser.parse() — normalizes V1/V2/conditions into groups format
|
|
27
|
+
→ CriteriaParser.getAudienceType() — 'static' or 'live'
|
|
28
|
+
│
|
|
29
|
+
├─ Static: StaticAudienceExecutor → SupabaseContactRepository → V2AudienceEngine
|
|
30
|
+
└─ Live: MemberRepository.listMembers() (injected)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**V2AudienceEngine** (~2200 lines) is the core. It evaluates groups of rules:
|
|
34
|
+
- **Property rules** (`kind='property'`) — query `contacts` table via Supabase
|
|
35
|
+
- **Event rules** (`kind='event'`) — routed to `ClickHouseEventQueryExecutor` when available, falls back to paginated Supabase + JS aggregation
|
|
36
|
+
|
|
37
|
+
### Criteria formats
|
|
38
|
+
|
|
39
|
+
Three formats supported (CriteriaParser normalizes all to V2 groups via `coerceCriteriaToGroups`):
|
|
40
|
+
- `groups[]` — V2 preferred. Rules have `kind`, `eventName`, `field`, `op`, `frequency`, `attributes`, `time`, `negate`, `interest`, `filters[]`
|
|
41
|
+
- `filters[]` — V1 legacy. Special: `field='event'` becomes event rule; `field='custom_field'` uses `customFieldKey`
|
|
42
|
+
- `conditions[]` — normalized legacy
|
|
43
|
+
|
|
44
|
+
Live audience types: `live-actions`, `live-page-visit`, `live-referrer`, `live-page-count`. Everything else is `static`.
|
|
45
|
+
|
|
46
|
+
### Database backends
|
|
47
|
+
|
|
48
|
+
- **Supabase (PostgreSQL)**: contacts, properties (JSONB), project settings. Always required.
|
|
49
|
+
- **ClickHouse** (optional): event queries. Replaces N paginated Supabase queries with single aggregation queries. Enabled via `clickhouseClient` in `AudienceBuilderConfig`.
|
|
50
|
+
|
|
51
|
+
### Key tables
|
|
52
|
+
|
|
53
|
+
- `contacts` — `id`, `reachy_id`, `email`, `properties` (JSONB for custom fields), `is_subscribed`, `created_at`, `updated_at`
|
|
54
|
+
- `contact_events` — `contact_id`, `reachy_id`, `event_name`, `event_data` (JSON), `event_timestamp`, keyed by `organization_id + project_id + event_name`. Also has denormalized columns: `current_url`, `domain`, `path`, `referrer`, `page_title`, `utm_*`, `session_id`, `session_is_new`
|
|
55
|
+
- `projects` — `settings.timezone` (IANA timezone string)
|
|
56
|
+
|
|
57
|
+
## V2AudienceEngine internals
|
|
58
|
+
|
|
59
|
+
### Identity resolution (3-tier fallback)
|
|
60
|
+
|
|
61
|
+
Event rows are resolved to contact UUIDs in this order:
|
|
62
|
+
1. `row.reachy_id` → lookup in `reachyIdToContactId` map
|
|
63
|
+
2. `row.contact_id` → validate against `allContactIds` set
|
|
64
|
+
3. Email from `event_data` (checks: `email`, `user_email`, `userEmail`, `contact_email`, `contactEmail`) → lookup in `emailToContactId`
|
|
65
|
+
|
|
66
|
+
Identity maps are lazy-loaded: only when criteria has event rules or negate rules.
|
|
67
|
+
|
|
68
|
+
### Property rules — JSONB patterns
|
|
69
|
+
|
|
70
|
+
Known columns (`email`, `first_name`, `last_name`, `phone`, `is_subscribed`, `created_at`, `updated_at`, `name`) query directly. Unknown fields use `properties->>{field}`.
|
|
71
|
+
|
|
72
|
+
Three special handling paths for JSONB fields:
|
|
73
|
+
- **Numeric JSONB** (`shouldNumericJsonb`): When operator is `>`, `>=`, `<`, `<=`, `between` — fetches `id, properties`, then compares in JS (Supabase JSONB numeric comparison is unreliable)
|
|
74
|
+
- **Negation JSONB** (`shouldManualJsonbNegation`): `not_equals`/`not_contains` on JSONB — fetches all, filters in JS (handles null semantics correctly)
|
|
75
|
+
- **is_not_empty on JSONB**: Uses `filter(propertyObj, 'cs', '{"keyName":')` to check key existence in JSON object
|
|
76
|
+
|
|
77
|
+
### Event rules — evaluation paths
|
|
78
|
+
|
|
79
|
+
ClickHouse executor has 4 optimized paths:
|
|
80
|
+
1. **First Time**: `GROUP BY contact_id HAVING min(event_timestamp) >= window_start`
|
|
81
|
+
2. **Last Time**: `GROUP BY contact_id HAVING max(event_timestamp) <= window_end`
|
|
82
|
+
3. **Pure Frequency**: `GROUP BY contact_id` with `count()`/`sum()`/`avg()` + `HAVING`
|
|
83
|
+
4. **Fetch & Process**: Fetch rows, apply in-memory filters (time_of_day, day_of_week, day_of_month, event_property, interest)
|
|
84
|
+
|
|
85
|
+
Supabase fallback: paginated `fetchAll()` + JS aggregation. First/last time uses chunked N+1 pattern (500 IDs per chunk, separate queries for `contact_id` and `reachy_id`).
|
|
86
|
+
|
|
87
|
+
### Live presets
|
|
88
|
+
|
|
89
|
+
- `live-page-visit`: Filters on `path`/`current_url` ILIKE + `domain` ILIKE
|
|
90
|
+
- `live-referrer`: `session_is_new=true` + referrer/UTM ILIKE
|
|
91
|
+
- `live-page-count`: In-memory count threshold
|
|
92
|
+
|
|
93
|
+
### Interest feature
|
|
94
|
+
|
|
95
|
+
- **predominantly**: Contact included if matching value count >= any other single value count
|
|
96
|
+
- **at_least X%**: Contact included if matching_count / total >= threshold
|
|
97
|
+
|
|
98
|
+
### Group evaluation strategy
|
|
99
|
+
|
|
100
|
+
- **OR groups**: All rules run in parallel (`Promise.all`), results unioned
|
|
101
|
+
- **AND/NOT groups**: Sequential with early exit on empty set
|
|
102
|
+
- **Between groups**: If all combine with OR, run in parallel; otherwise sequential with early exit
|
|
103
|
+
- Single-contact evaluation (`matchesContact`) also has early exits: AND+false→false, OR+true→true
|
|
104
|
+
|
|
105
|
+
## Performance safeguards
|
|
106
|
+
|
|
107
|
+
| Context | Max rows | Location |
|
|
108
|
+
|---------|----------|----------|
|
|
109
|
+
| Supabase contacts fetch | 500,000 | V2AudienceEngine `fetchAll` default |
|
|
110
|
+
| Supabase event queries | 200,000 | V2AudienceEngine `MAX_EVENT_ROWS` |
|
|
111
|
+
| ClickHouse fetch queries | 200,000 | ClickHouseEventQueryExecutor `MAX_FETCH_ROWS` |
|
|
112
|
+
| first/last_time boundary | 50,000 per chunk | V2AudienceEngine offset guard |
|
|
113
|
+
|
|
114
|
+
- **Timezone cache**: Static `_tzCache` with 5-min TTL, keyed by `orgId:projectId`
|
|
115
|
+
- **Lazy contact loading**: Identity maps only loaded when needed (event rules or negate)
|
|
116
|
+
- **Minimal SELECT**: Event queries select only needed fields (`contact_id, reachy_id` base; add `event_data`/`event_timestamp` only when required)
|
|
117
|
+
- **Set operations optimized**: `intersect` iterates smaller set; no intermediate array allocations
|
|
118
|
+
|
|
119
|
+
## Security
|
|
120
|
+
|
|
121
|
+
- **ClickHouse**: All user values via `query_params` (`{param:Type}` syntax). Field expressions validated with `^[a-zA-Z0-9_]+$` allowlist.
|
|
122
|
+
- **Supabase**: Uses PostgREST query builder (parameterized by default).
|
|
123
|
+
|
|
124
|
+
## RFM Engine
|
|
125
|
+
|
|
126
|
+
`RfmEngine` computes Recency-Frequency scores (1-5 each) using percentile cuts (20th/40th/60th/80th). 10 segments: Champions, Loyal Users, Potential Loyalists, New Users, Promising, Needing Attention, About to Sleep, Cannot Lose Them, At Risk, Hibernating.
|
|
127
|
+
|
|
128
|
+
`RfmSegmentBuilder` converts RFM thresholds into executable audience criteria (groups format with event rules + frequency filters).
|
|
129
|
+
|
|
130
|
+
## Field mapping reference
|
|
131
|
+
|
|
132
|
+
`mapAudienceFieldToContactField`: `name`→`first_name`. All other known fields map to themselves. Unknown fields fall through to `properties->>{field}`.
|
|
133
|
+
|
|
134
|
+
Date normalization (`normalizeDateBoundary`): Accepts `YYYY-MM-DD`, `DD/MM/YYYY`, ISO timestamps. Start boundary → `00:00:00Z`. End boundary → start of next day (exclusive `.lt()`).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudienceModule.d.ts","sourceRoot":"","sources":["../src/AudienceModule.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,SAAS,CAAA;AAuBhB,qBAAa,cAAc;IACzB,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAAwB;gBAElC,MAAM,GAAE,qBAA0B;
|
|
1
|
+
{"version":3,"file":"AudienceModule.d.ts","sourceRoot":"","sources":["../src/AudienceModule.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EACnB,MAAM,SAAS,CAAA;AAuBhB,qBAAa,cAAc;IACzB,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,gBAAgB,CAAK;IAC7B,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAAwB;gBAElC,MAAM,GAAE,qBAA0B;IA4B9C,eAAe,CAAC,YAAY,EAAE;QAC5B,iBAAiB,CAAC,EAAE,GAAG,CAAA;QACvB,kBAAkB,CAAC,EAAE,GAAG,CAAA;QACxB,gBAAgB,CAAC,EAAE,GAAG,CAAA;KACvB;IAoBK,YAAY,CAChB,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EACnC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,uBAAuB,CAAC;IAc7B,eAAe,CACnB,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EACnC,OAAO,EAAE,IAAI,CAAC,oBAAoB,EAAE,YAAY,CAAC,GAChD,OAAO,CAAC,MAAM,CAAC;IAQZ,aAAa,CACjB,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EACnC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAiBjB,cAAc,CAClB,QAAQ,EAAE,MAAM,GAAG,gBAAgB,EACnC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAgCb,cAAc,CAAC,IAAI,EAAE,kBAAkB;;;;IA8BvC,cAAc,CAClB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,kBAAkB,EAC9B,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM;;;;IAmCb,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAUrE,cAAc,CAAC,EAAE,EAAE,MAAM;IAc/B,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAiCjD,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAAE,EACpB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,UAAU,GAAG,UAAuB;IAkBxC,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAqBhD,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB;;;;IAQpD,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,QAAQ,GAAG,MAAM;YAYzD,gBAAgB;CA6B/B"}
|
package/dist/AudienceModule.js
CHANGED
|
@@ -10,6 +10,7 @@ class AudienceModule {
|
|
|
10
10
|
if (config.supabaseClient) {
|
|
11
11
|
const repo = new SupabaseContactRepository_1.SupabaseContactRepository({
|
|
12
12
|
supabaseClient: config.supabaseClient,
|
|
13
|
+
clickhouseClient: config.clickhouseClient,
|
|
13
14
|
debug: !!config.enableDebugLogs,
|
|
14
15
|
logger: console
|
|
15
16
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudienceModule.js","sourceRoot":"","sources":["../src/AudienceModule.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"AudienceModule.js","sourceRoot":"","sources":["../src/AudienceModule.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,11 +7,16 @@ export declare class V2AudienceEngine {
|
|
|
7
7
|
private supabase;
|
|
8
8
|
private debug;
|
|
9
9
|
private logger;
|
|
10
|
+
private chExecutor;
|
|
11
|
+
private static _tzCache;
|
|
12
|
+
private static TZ_CACHE_TTL;
|
|
10
13
|
constructor(params: {
|
|
11
14
|
supabaseClient: any;
|
|
15
|
+
clickhouseClient?: any;
|
|
12
16
|
debug?: boolean;
|
|
13
17
|
logger?: Logger;
|
|
14
18
|
});
|
|
19
|
+
private getProjectTimezone;
|
|
15
20
|
getContactIdsByAudienceCriteriaV2(organizationId: string, projectId: string, criteriaRaw: any): Promise<Set<string>>;
|
|
16
21
|
matchesContactByAudienceCriteriaV2(organizationId: string, projectId: string, criteriaRaw: any, contactId: string): Promise<boolean>;
|
|
17
22
|
private dlog;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"V2AudienceEngine.d.ts","sourceRoot":"","sources":["../../src/engine/V2AudienceEngine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"V2AudienceEngine.d.ts","sourceRoot":"","sources":["../../src/engine/V2AudienceEngine.ts"],"names":[],"mappings":"AAIA,KAAK,MAAM,GAAG;IACZ,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC7B,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC9B,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CAChC,CAAA;AAgRD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,UAAU,CAA4C;IAE9D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAuD;IAC9E,OAAO,CAAC,MAAM,CAAC,YAAY,CAAgB;gBAE/B,MAAM,EAAE;QAAE,cAAc,EAAE,GAAG,CAAC;QAAC,gBAAgB,CAAC,EAAE,GAAG,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;YAUvF,kBAAkB;IAyB1B,iCAAiC,CACrC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,GAAG,GACf,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAw/BjB,kCAAkC,CACtC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,GAAG,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC;IAmsBnB,OAAO,CAAC,IAAI;CAIb"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.V2AudienceEngine = void 0;
|
|
4
4
|
const CriteriaParser_1 = require("../builders/CriteriaParser");
|
|
5
|
+
const ClickHouseEventQueryExecutor_1 = require("../executors/ClickHouseEventQueryExecutor");
|
|
5
6
|
const getByPath = (obj, dottedPath) => {
|
|
6
7
|
if (!obj || !dottedPath)
|
|
7
8
|
return undefined;
|
|
@@ -315,13 +316,22 @@ const applyEventRuleFilters = (rows, filters, opts) => {
|
|
|
315
316
|
};
|
|
316
317
|
class V2AudienceEngine {
|
|
317
318
|
constructor(params) {
|
|
319
|
+
this.chExecutor = null;
|
|
318
320
|
this.supabase = params.supabaseClient;
|
|
319
321
|
this.debug = !!params.debug;
|
|
320
322
|
this.logger = params.logger || console;
|
|
323
|
+
if (params.clickhouseClient) {
|
|
324
|
+
this.chExecutor = new ClickHouseEventQueryExecutor_1.ClickHouseEventQueryExecutor(params.clickhouseClient, params.logger || console);
|
|
325
|
+
if (this.debug)
|
|
326
|
+
this.logger.log('[V2AudienceEngine] ClickHouse executor initialized');
|
|
327
|
+
}
|
|
321
328
|
}
|
|
322
|
-
async
|
|
323
|
-
|
|
324
|
-
|
|
329
|
+
async getProjectTimezone(organizationId, projectId) {
|
|
330
|
+
const cacheKey = `${organizationId}:${projectId}`;
|
|
331
|
+
const cached = V2AudienceEngine._tzCache.get(cacheKey);
|
|
332
|
+
if (cached && Date.now() - cached.fetchedAt < V2AudienceEngine.TZ_CACHE_TTL) {
|
|
333
|
+
return cached.tz;
|
|
334
|
+
}
|
|
325
335
|
try {
|
|
326
336
|
const { data } = await this.supabase
|
|
327
337
|
.from('projects')
|
|
@@ -330,12 +340,20 @@ class V2AudienceEngine {
|
|
|
330
340
|
.eq('id', projectId)
|
|
331
341
|
.single();
|
|
332
342
|
const tzCandidate = data?.settings?.timezone;
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
343
|
+
const tz = (typeof tzCandidate === 'string' && isValidIanaTimezone(tzCandidate))
|
|
344
|
+
? tzCandidate.trim()
|
|
345
|
+
: 'UTC';
|
|
346
|
+
V2AudienceEngine._tzCache.set(cacheKey, { tz, fetchedAt: Date.now() });
|
|
347
|
+
return tz;
|
|
336
348
|
}
|
|
337
349
|
catch {
|
|
350
|
+
V2AudienceEngine._tzCache.set(cacheKey, { tz: 'UTC', fetchedAt: Date.now() });
|
|
351
|
+
return 'UTC';
|
|
338
352
|
}
|
|
353
|
+
}
|
|
354
|
+
async getContactIdsByAudienceCriteriaV2(organizationId, projectId, criteriaRaw) {
|
|
355
|
+
let criteria = CriteriaParser_1.CriteriaParser.parse(criteriaRaw);
|
|
356
|
+
const projectTimezone = await this.getProjectTimezone(organizationId, projectId);
|
|
339
357
|
if ((!Array.isArray(criteria.groups) || criteria.groups.length === 0) &&
|
|
340
358
|
(Array.isArray(criteria.filters) || Array.isArray(criteria.conditions))) {
|
|
341
359
|
criteria = coerceCriteriaToGroups(criteria);
|
|
@@ -351,7 +369,8 @@ class V2AudienceEngine {
|
|
|
351
369
|
return new Set();
|
|
352
370
|
}
|
|
353
371
|
const typeId = String(criteria?.type || '');
|
|
354
|
-
const
|
|
372
|
+
const MAX_FETCH_ROWS = 500000;
|
|
373
|
+
const fetchAll = async (baseQuery, pageSize, maxRows = MAX_FETCH_ROWS) => {
|
|
355
374
|
let offset = 0;
|
|
356
375
|
let out = [];
|
|
357
376
|
while (true) {
|
|
@@ -361,35 +380,72 @@ class V2AudienceEngine {
|
|
|
361
380
|
if (!data || data.length === 0)
|
|
362
381
|
break;
|
|
363
382
|
out = out.concat(data);
|
|
383
|
+
if (out.length >= maxRows) {
|
|
384
|
+
this.dlog('fetchAll: max rows reached', { maxRows, fetched: out.length });
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
364
387
|
if (data.length < pageSize)
|
|
365
388
|
break;
|
|
366
389
|
offset += pageSize;
|
|
367
390
|
}
|
|
368
391
|
return out;
|
|
369
392
|
};
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
393
|
+
const groups = criteria.groups;
|
|
394
|
+
const hasNegate = groups.some((g) => (g.rules || []).some((r) => r.negate));
|
|
395
|
+
const hasEventRules = groups.some((g) => (g.rules || []).some((r) => r.kind === 'event'));
|
|
396
|
+
let allContactIds = new Set();
|
|
397
|
+
let reachyIdToContactId = new Map();
|
|
398
|
+
let contactIdToReachyId = new Map();
|
|
399
|
+
let emailToContactId = new Map();
|
|
400
|
+
let _contactsLoaded = false;
|
|
401
|
+
const ensureContactsLoaded = async () => {
|
|
402
|
+
if (_contactsLoaded)
|
|
403
|
+
return;
|
|
404
|
+
_contactsLoaded = true;
|
|
405
|
+
const allContacts = await fetchAll(this.supabase
|
|
406
|
+
.from('contacts')
|
|
407
|
+
.select('id, reachy_id, email')
|
|
408
|
+
.eq('organization_id', organizationId)
|
|
409
|
+
.eq('project_id', projectId), 1000);
|
|
410
|
+
allContactIds = new Set((allContacts || []).map((c) => c.id));
|
|
411
|
+
for (const c of allContacts || []) {
|
|
412
|
+
const rid = c?.reachy_id ? String(c.reachy_id).trim() : '';
|
|
413
|
+
const cid = c?.id ? String(c.id).trim() : '';
|
|
414
|
+
if (rid && cid) {
|
|
415
|
+
reachyIdToContactId.set(rid, cid);
|
|
416
|
+
contactIdToReachyId.set(cid, rid);
|
|
417
|
+
}
|
|
418
|
+
const email = c?.email ? String(c.email).trim().toLowerCase() : '';
|
|
419
|
+
if (email && cid)
|
|
420
|
+
emailToContactId.set(email, cid);
|
|
385
421
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
422
|
+
};
|
|
423
|
+
if (hasNegate || hasEventRules) {
|
|
424
|
+
await ensureContactsLoaded();
|
|
389
425
|
}
|
|
390
|
-
const union = (a, b) =>
|
|
391
|
-
|
|
392
|
-
|
|
426
|
+
const union = (a, b) => {
|
|
427
|
+
const result = new Set(a);
|
|
428
|
+
for (const x of b)
|
|
429
|
+
result.add(x);
|
|
430
|
+
return result;
|
|
431
|
+
};
|
|
432
|
+
const intersect = (a, b) => {
|
|
433
|
+
const [smaller, larger] = a.size <= b.size ? [a, b] : [b, a];
|
|
434
|
+
const result = new Set();
|
|
435
|
+
for (const x of smaller) {
|
|
436
|
+
if (larger.has(x))
|
|
437
|
+
result.add(x);
|
|
438
|
+
}
|
|
439
|
+
return result;
|
|
440
|
+
};
|
|
441
|
+
const diff = (a, b) => {
|
|
442
|
+
const result = new Set();
|
|
443
|
+
for (const x of a) {
|
|
444
|
+
if (!b.has(x))
|
|
445
|
+
result.add(x);
|
|
446
|
+
}
|
|
447
|
+
return result;
|
|
448
|
+
};
|
|
393
449
|
const resolveEventContactId = (row) => {
|
|
394
450
|
const rawReachyId = row?.reachy_id ? String(row.reachy_id).trim() : '';
|
|
395
451
|
if (rawReachyId) {
|
|
@@ -416,12 +472,33 @@ class V2AudienceEngine {
|
|
|
416
472
|
};
|
|
417
473
|
const evalEventRule = async (rule) => {
|
|
418
474
|
const cfg = criteria?.config || {};
|
|
475
|
+
if (this.chExecutor) {
|
|
476
|
+
try {
|
|
477
|
+
return await this.chExecutor.execute(rule, criteria, organizationId, projectId, projectTimezone, reachyIdToContactId, contactIdToReachyId, allContactIds);
|
|
478
|
+
}
|
|
479
|
+
catch (chErr) {
|
|
480
|
+
this.logger.warn('[V2AudienceEngine] ClickHouse evalEventRule failed, falling back to Supabase:', chErr);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
419
483
|
const effectiveEventName = cfg.eventType && String(cfg.eventType).trim() !== ''
|
|
420
484
|
? String(cfg.eventType)
|
|
421
485
|
: String(rule.eventName);
|
|
486
|
+
const ruleFiltersPrecheck = Array.isArray(rule.filters) ? rule.filters : [];
|
|
487
|
+
const needsEventData = !!((rule.interest && rule.interest.key) ||
|
|
488
|
+
ruleFiltersPrecheck.some((f) => ['event_property', 'time_of_day', 'day_of_week', 'day_of_month'].includes(String(f?.type || '').trim())) ||
|
|
489
|
+
(rule.frequency && rule.frequency.type && rule.frequency.type !== 'count') ||
|
|
490
|
+
typeId === 'live-page-count');
|
|
491
|
+
const needsTimestamp = !!(ruleFiltersPrecheck.some((f) => ['first_time', 'last_time', 'time_of_day', 'day_of_week', 'day_of_month'].includes(String(f?.type || '').trim())));
|
|
492
|
+
let selectFields = 'contact_id, reachy_id';
|
|
493
|
+
if (needsEventData)
|
|
494
|
+
selectFields += ', event_data';
|
|
495
|
+
if (needsTimestamp)
|
|
496
|
+
selectFields += ', event_timestamp';
|
|
497
|
+
if (needsEventData || needsTimestamp)
|
|
498
|
+
selectFields += ', event_name';
|
|
422
499
|
let query = this.supabase
|
|
423
500
|
.from('contact_events')
|
|
424
|
-
.select(
|
|
501
|
+
.select(selectFields)
|
|
425
502
|
.eq('organization_id', organizationId)
|
|
426
503
|
.eq('project_id', projectId)
|
|
427
504
|
.eq('event_name', effectiveEventName);
|
|
@@ -622,7 +699,8 @@ class V2AudienceEngine {
|
|
|
622
699
|
if (this.debug)
|
|
623
700
|
this.logger.warn('[AUDIENCE_MODULE_ENGINE] event attributes filter error');
|
|
624
701
|
}
|
|
625
|
-
const
|
|
702
|
+
const MAX_EVENT_ROWS = 200000;
|
|
703
|
+
const data = await fetchAll(query, 1000, MAX_EVENT_ROWS);
|
|
626
704
|
if (!data || data.length === 0)
|
|
627
705
|
return new Set();
|
|
628
706
|
let rows = data;
|
|
@@ -1208,41 +1286,78 @@ class V2AudienceEngine {
|
|
|
1208
1286
|
return new Set();
|
|
1209
1287
|
return new Set(data.map((r) => r.id));
|
|
1210
1288
|
};
|
|
1289
|
+
const evalRule = (rule) => rule.kind === 'event' ? evalEventRule(rule) : evalPropertyRule(rule);
|
|
1211
1290
|
const evalGroup = async (group) => {
|
|
1291
|
+
const rules = group.rules || [];
|
|
1292
|
+
if (rules.length === 0)
|
|
1293
|
+
return new Set();
|
|
1294
|
+
const op = group.operator;
|
|
1295
|
+
if (op === 'OR') {
|
|
1296
|
+
const results = await Promise.all(rules.map(async (rule) => {
|
|
1297
|
+
const set = await evalRule(rule);
|
|
1298
|
+
return rule.negate ? diff(allContactIds, set) : set;
|
|
1299
|
+
}));
|
|
1300
|
+
let acc = results[0];
|
|
1301
|
+
for (let i = 1; i < results.length; i++) {
|
|
1302
|
+
acc = union(acc, results[i]);
|
|
1303
|
+
}
|
|
1304
|
+
return acc;
|
|
1305
|
+
}
|
|
1212
1306
|
let acc = null;
|
|
1213
|
-
for (const rule of
|
|
1214
|
-
const set =
|
|
1215
|
-
const
|
|
1216
|
-
const s = shouldNegate ? diff(allContactIds, set) : set;
|
|
1307
|
+
for (const rule of rules) {
|
|
1308
|
+
const set = await evalRule(rule);
|
|
1309
|
+
const s = rule.negate ? diff(allContactIds, set) : set;
|
|
1217
1310
|
if (acc == null) {
|
|
1218
1311
|
acc = s;
|
|
1219
1312
|
}
|
|
1220
1313
|
else {
|
|
1221
|
-
if (
|
|
1314
|
+
if (op === 'AND')
|
|
1222
1315
|
acc = intersect(acc, s);
|
|
1223
|
-
else if (
|
|
1224
|
-
acc = union(acc, s);
|
|
1225
|
-
else if (group.operator === 'NOT')
|
|
1316
|
+
else if (op === 'NOT')
|
|
1226
1317
|
acc = diff(acc, s);
|
|
1227
1318
|
}
|
|
1319
|
+
if (acc.size === 0)
|
|
1320
|
+
return acc;
|
|
1228
1321
|
}
|
|
1229
1322
|
return acc || new Set();
|
|
1230
1323
|
};
|
|
1324
|
+
const allGroups = criteria.groups;
|
|
1231
1325
|
let result = null;
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1326
|
+
const allCombineWithOr = allGroups.length > 1 && allGroups.every((g, i) => {
|
|
1327
|
+
if (i === 0)
|
|
1328
|
+
return true;
|
|
1329
|
+
return String(g.combineOperator || g.operator || 'AND').toUpperCase() === 'OR';
|
|
1330
|
+
});
|
|
1331
|
+
if (allCombineWithOr) {
|
|
1332
|
+
const groupResults = await Promise.all(allGroups.map((g) => evalGroup(g)));
|
|
1333
|
+
result = groupResults[0];
|
|
1334
|
+
for (let i = 1; i < groupResults.length; i++) {
|
|
1335
|
+
result = union(result, groupResults[i]);
|
|
1237
1336
|
}
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1337
|
+
}
|
|
1338
|
+
else {
|
|
1339
|
+
for (let i = 0; i < allGroups.length; i++) {
|
|
1340
|
+
const group = allGroups[i];
|
|
1341
|
+
const gset = await evalGroup(group);
|
|
1342
|
+
if (result == null) {
|
|
1343
|
+
result = gset;
|
|
1344
|
+
}
|
|
1345
|
+
else {
|
|
1346
|
+
const betweenOp = String(group.combineOperator || group.operator || 'AND').toUpperCase();
|
|
1347
|
+
if (betweenOp === 'AND')
|
|
1348
|
+
result = intersect(result, gset);
|
|
1349
|
+
else if (betweenOp === 'OR')
|
|
1350
|
+
result = union(result, gset);
|
|
1351
|
+
else if (betweenOp === 'NOT')
|
|
1352
|
+
result = diff(result, gset);
|
|
1353
|
+
}
|
|
1354
|
+
if (result.size === 0) {
|
|
1355
|
+
const nextOp = i + 1 < allGroups.length
|
|
1356
|
+
? String((allGroups[i + 1].combineOperator || allGroups[i + 1].operator || 'AND')).toUpperCase()
|
|
1357
|
+
: '';
|
|
1358
|
+
if (nextOp === 'AND' || nextOp === 'NOT')
|
|
1359
|
+
break;
|
|
1360
|
+
}
|
|
1246
1361
|
}
|
|
1247
1362
|
}
|
|
1248
1363
|
const finalSet = result || new Set();
|
|
@@ -1259,21 +1374,7 @@ class V2AudienceEngine {
|
|
|
1259
1374
|
return false;
|
|
1260
1375
|
}
|
|
1261
1376
|
const typeId = String(criteria?.type || '');
|
|
1262
|
-
|
|
1263
|
-
try {
|
|
1264
|
-
const { data } = await this.supabase
|
|
1265
|
-
.from('projects')
|
|
1266
|
-
.select('settings')
|
|
1267
|
-
.eq('organization_id', organizationId)
|
|
1268
|
-
.eq('id', projectId)
|
|
1269
|
-
.single();
|
|
1270
|
-
const tzCandidate = data?.settings?.timezone;
|
|
1271
|
-
if (typeof tzCandidate === 'string' && isValidIanaTimezone(tzCandidate)) {
|
|
1272
|
-
projectTimezone = tzCandidate.trim();
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
catch {
|
|
1276
|
-
}
|
|
1377
|
+
const projectTimezone = await this.getProjectTimezone(organizationId, projectId);
|
|
1277
1378
|
const { data: contactRow } = await this.supabase
|
|
1278
1379
|
.from('contacts')
|
|
1279
1380
|
.select('id, reachy_id, email')
|
|
@@ -1284,6 +1385,22 @@ class V2AudienceEngine {
|
|
|
1284
1385
|
const reachyId = contactRow?.reachy_id ? String(contactRow.reachy_id).trim() : '';
|
|
1285
1386
|
const evalEventRuleForContact = async (rule) => {
|
|
1286
1387
|
const cfg = criteria?.config || {};
|
|
1388
|
+
if (this.chExecutor) {
|
|
1389
|
+
try {
|
|
1390
|
+
const singleContactIdToReachyId = new Map();
|
|
1391
|
+
const singleReachyIdToContactId = new Map();
|
|
1392
|
+
const singleAllContactIds = new Set([contactId]);
|
|
1393
|
+
if (reachyId) {
|
|
1394
|
+
singleReachyIdToContactId.set(reachyId, contactId);
|
|
1395
|
+
singleContactIdToReachyId.set(contactId, reachyId);
|
|
1396
|
+
}
|
|
1397
|
+
const matchSet = await this.chExecutor.execute(rule, criteria, organizationId, projectId, projectTimezone, singleReachyIdToContactId, singleContactIdToReachyId, singleAllContactIds);
|
|
1398
|
+
return matchSet.has(contactId);
|
|
1399
|
+
}
|
|
1400
|
+
catch (chErr) {
|
|
1401
|
+
this.logger.warn('[V2AudienceEngine] ClickHouse evalEventRuleForContact failed, falling back to Supabase:', chErr);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1287
1404
|
const effectiveEventName = cfg.eventType && String(cfg.eventType).trim() !== ''
|
|
1288
1405
|
? String(cfg.eventType)
|
|
1289
1406
|
: String(rule.eventName);
|
|
@@ -1948,27 +2065,37 @@ class V2AudienceEngine {
|
|
|
1948
2065
|
return res;
|
|
1949
2066
|
};
|
|
1950
2067
|
const evalGroupForContact = async (group) => {
|
|
2068
|
+
const rules = group.rules || [];
|
|
2069
|
+
if (rules.length === 0)
|
|
2070
|
+
return false;
|
|
2071
|
+
const op = group.operator;
|
|
1951
2072
|
let acc = null;
|
|
1952
|
-
for (const rule of
|
|
2073
|
+
for (const rule of rules) {
|
|
1953
2074
|
const r = await evalRuleForContact(rule);
|
|
1954
|
-
if (acc == null)
|
|
2075
|
+
if (acc == null) {
|
|
1955
2076
|
acc = r;
|
|
2077
|
+
}
|
|
1956
2078
|
else {
|
|
1957
|
-
if (
|
|
2079
|
+
if (op === 'AND')
|
|
1958
2080
|
acc = acc && r;
|
|
1959
|
-
else if (
|
|
2081
|
+
else if (op === 'OR')
|
|
1960
2082
|
acc = acc || r;
|
|
1961
|
-
else if (
|
|
2083
|
+
else if (op === 'NOT')
|
|
1962
2084
|
acc = acc && !r;
|
|
1963
2085
|
}
|
|
2086
|
+
if (op === 'AND' && acc === false)
|
|
2087
|
+
return false;
|
|
2088
|
+
if (op === 'OR' && acc === true)
|
|
2089
|
+
return true;
|
|
1964
2090
|
}
|
|
1965
2091
|
return !!acc;
|
|
1966
2092
|
};
|
|
1967
2093
|
let result = null;
|
|
1968
2094
|
for (const group of criteria.groups) {
|
|
1969
2095
|
const g = await evalGroupForContact(group);
|
|
1970
|
-
if (result == null)
|
|
2096
|
+
if (result == null) {
|
|
1971
2097
|
result = g;
|
|
2098
|
+
}
|
|
1972
2099
|
else {
|
|
1973
2100
|
const betweenOp = String(group.combineOperator || group.operator || 'AND').toUpperCase();
|
|
1974
2101
|
if (betweenOp === 'AND')
|
|
@@ -1978,6 +2105,15 @@ class V2AudienceEngine {
|
|
|
1978
2105
|
else if (betweenOp === 'NOT')
|
|
1979
2106
|
result = result && !g;
|
|
1980
2107
|
}
|
|
2108
|
+
if (result === false) {
|
|
2109
|
+
const remaining = criteria.groups.slice(criteria.groups.indexOf(group) + 1);
|
|
2110
|
+
const allAnd = remaining.every((g2) => {
|
|
2111
|
+
const op2 = String(g2.combineOperator || g2.operator || 'AND').toUpperCase();
|
|
2112
|
+
return op2 === 'AND' || op2 === 'NOT';
|
|
2113
|
+
});
|
|
2114
|
+
if (allAnd)
|
|
2115
|
+
return false;
|
|
2116
|
+
}
|
|
1981
2117
|
}
|
|
1982
2118
|
return !!result;
|
|
1983
2119
|
}
|
|
@@ -1988,6 +2124,8 @@ class V2AudienceEngine {
|
|
|
1988
2124
|
}
|
|
1989
2125
|
}
|
|
1990
2126
|
exports.V2AudienceEngine = V2AudienceEngine;
|
|
2127
|
+
V2AudienceEngine._tzCache = new Map();
|
|
2128
|
+
V2AudienceEngine.TZ_CACHE_TTL = 5 * 60 * 1000;
|
|
1991
2129
|
function jsonTextAccessor(base, key) {
|
|
1992
2130
|
const safeKey = String(key || '').trim();
|
|
1993
2131
|
return `${base}->>${safeKey}`;
|