vc-cdp-rn-sdk 0.1.0
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/README.md +539 -0
- package/dist/CdpRnSdk.d.ts +129 -0
- package/dist/CdpRnSdk.d.ts.map +1 -0
- package/dist/CdpRnSdk.js +521 -0
- package/dist/CdpRnSdk.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +150 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/crypto.d.ts +17 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +60 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/device.d.ts +3 -0
- package/dist/utils/device.d.ts.map +1 -0
- package/dist/utils/device.js +58 -0
- package/dist/utils/device.js.map +1 -0
- package/dist/utils/storage.d.ts +12 -0
- package/dist/utils/storage.d.ts.map +1 -0
- package/dist/utils/storage.js +51 -0
- package/dist/utils/storage.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
# vc-cdp-rn-sdk
|
|
2
|
+
|
|
3
|
+
CDP SDK cho React Native — tracking events và user profiles cho hệ thống CDP nội bộ VietCredit. Hỗ trợ cả **iOS** và **Android**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Mục lục
|
|
8
|
+
|
|
9
|
+
- [Cài đặt](#cài-đặt)
|
|
10
|
+
- [Khởi tạo](#khởi-tạo)
|
|
11
|
+
- [Luồng hoạt động](#luồng-hoạt-động)
|
|
12
|
+
- [User / Profile](#user--profile)
|
|
13
|
+
- [Đăng nhập](#đăng-nhập-identifyuser)
|
|
14
|
+
- [Cập nhật profile](#cập-nhật-profile-updateprofile)
|
|
15
|
+
- [Lấy thông tin profile](#lấy-thông-tin-profile-getprofile)
|
|
16
|
+
- [Trait setters](#trait-setters-chainable)
|
|
17
|
+
- [Consents](#consents)
|
|
18
|
+
- [Scores](#scores)
|
|
19
|
+
- [Products](#products)
|
|
20
|
+
- [Metadata](#metadata)
|
|
21
|
+
- [Campaign / UTM](#campaign--utm)
|
|
22
|
+
- [Push Token](#push-token)
|
|
23
|
+
- [Đăng xuất](#đăng-xuất)
|
|
24
|
+
- [Event Tracking](#event-tracking)
|
|
25
|
+
- [Track sự kiện](#track-sự-kiện)
|
|
26
|
+
- [Track màn hình](#track-màn-hình-screen)
|
|
27
|
+
- [Flush thủ công](#flush-thủ-công)
|
|
28
|
+
- [Lấy thông tin định danh](#lấy-thông-tin-định-danh)
|
|
29
|
+
- [Bảo mật](#bảo-mật)
|
|
30
|
+
- [Dependencies](#dependencies)
|
|
31
|
+
- [API Reference](#api-reference)
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Cài đặt
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm install vc-cdp-rn-sdk @react-native-async-storage/async-storage react-native-device-info crypto-js
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### iOS
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
cd ios && pod install
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Android
|
|
48
|
+
|
|
49
|
+
Không cần bước cấu hình thêm.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Khởi tạo
|
|
54
|
+
|
|
55
|
+
Gọi `CdpRnSdk.create()` **một lần duy nhất** tại entry point của app (ví dụ `App.tsx`). SDK dùng `AsyncStorage` nên init là bất đồng bộ.
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { CdpRnSdk } from 'vc-cdp-rn-sdk';
|
|
59
|
+
|
|
60
|
+
let cdp: CdpRnSdk;
|
|
61
|
+
|
|
62
|
+
export async function setupCdp() {
|
|
63
|
+
cdp = await CdpRnSdk.create({
|
|
64
|
+
apiKey: 'YOUR_API_KEY', // Bắt buộc — do CDP cấp
|
|
65
|
+
secretKey: 'YOUR_SECRET_KEY', // Bắt buộc — dùng ký HMAC + mã hoá AES
|
|
66
|
+
source: 'DOP', // Bắt buộc — kênh phát triển (khai báo với CDP trước)
|
|
67
|
+
serviceName: 'DOP', // Bắt buộc — DOP | LOS | LMS
|
|
68
|
+
|
|
69
|
+
// Tuỳ chọn
|
|
70
|
+
baseUrl: 'https://stg-ingestlog.vietcredit.com.vn', // mặc định: staging
|
|
71
|
+
isTest: true, // đánh dấu môi trường test
|
|
72
|
+
debug: true, // in log ra console
|
|
73
|
+
batchSize: 10, // gửi batch khi queue đủ n events (mặc định: 10)
|
|
74
|
+
batchInterval: 5000, // hoặc sau n ms dù chưa đủ batch (mặc định: 5000)
|
|
75
|
+
enableEncryption: true // mã hoá PII bằng AES-256-CBC (mặc định: true)
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
> **Lưu ý:** Các events được gọi trước khi `create()` hoàn thành sẽ được buffer lại và tự động gửi sau khi khởi tạo xong — không bị mất.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Luồng hoạt động
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
App khởi động
|
|
88
|
+
└─> CdpRnSdk.create(config)
|
|
89
|
+
│ - Tạo session_id mới (luôn fresh mỗi lần mở app)
|
|
90
|
+
│ - Load anonymous_id, device_id từ AsyncStorage (persistent)
|
|
91
|
+
│ - Load profile_id từ AsyncStorage (nếu đã login trước đó)
|
|
92
|
+
│ - Thu thập device info (brand, model, OS)
|
|
93
|
+
│
|
|
94
|
+
├─ User CHƯA login
|
|
95
|
+
│ └─> cdp.track(event)
|
|
96
|
+
│ profile_id = null, gắn anonymous_id + device_id + session_id
|
|
97
|
+
│ CDP sẽ identity-resolve khi user login sau
|
|
98
|
+
│
|
|
99
|
+
└─ User login
|
|
100
|
+
└─> cdp.identifyUser(userId, traits)
|
|
101
|
+
└─> POST /v1/profiles/track → nhận profile_id
|
|
102
|
+
└─> cdp.track(event)
|
|
103
|
+
profile_id được gắn vào mọi event tiếp theo
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Session ID:** Mỗi lần mở app tạo một `session_id` mới. `device_id` và `anonymous_id` được giữ nguyên giữa các lần mở.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## User / Profile
|
|
111
|
+
|
|
112
|
+
### Đăng nhập (`identifyUser`)
|
|
113
|
+
|
|
114
|
+
Gọi sau khi user đăng nhập thành công. SDK sẽ gọi `POST /v1/profiles/track`, nhận `profile_id` từ CDP và lưu vào storage để dùng cho các lần sau.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
await cdp.identifyUser('user_123', {
|
|
118
|
+
phone: '0901234567',
|
|
119
|
+
full_name: 'Nguyễn Văn A',
|
|
120
|
+
email: 'user@example.com',
|
|
121
|
+
gender: 'M', // 'M' | 'F' | 'O'
|
|
122
|
+
dob: '1990-01-15', // yyyy-MM-dd
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Tài khoản tổ chức (doanh nghiệp)
|
|
126
|
+
await cdp.identifyUser('org_456', { full_name: 'Công ty ABC' }, 'ORG');
|
|
127
|
+
|
|
128
|
+
// Alias ngắn gọn
|
|
129
|
+
await cdp.identify('user_123', { phone: '0901234567' });
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
| Tham số | Kiểu | Bắt buộc | Mô tả |
|
|
133
|
+
|---|---|---|---|
|
|
134
|
+
| `userId` | `string` | ✓ | Mã user trong hệ thống |
|
|
135
|
+
| `traits` | `UserTraits` | | Thông tin nhân khẩu học |
|
|
136
|
+
| `partyType` | `'PERSON' \| 'ORG'` | | Mặc định `'PERSON'` |
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
### Cập nhật profile (`updateProfile`)
|
|
141
|
+
|
|
142
|
+
Force-update profile theo `profile_id` — không trigger identity resolution. Dùng khi cần cập nhật một số trường cụ thể sau khi đã có `profile_id`.
|
|
143
|
+
|
|
144
|
+
Gọi `POST /v1/profiles/update`.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
await cdp.updateProfile({
|
|
148
|
+
traits: {
|
|
149
|
+
kyc_status: 'verified',
|
|
150
|
+
mps_verified: true,
|
|
151
|
+
},
|
|
152
|
+
consents: [
|
|
153
|
+
{ consent_type: 'marketing_email', status: true, consent_date: '2025-06-01' },
|
|
154
|
+
],
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Cập nhật profile_id khác (không phải profile hiện tại)
|
|
158
|
+
await cdp.updateProfile({
|
|
159
|
+
profile_id: 'cdp_profile_xyz',
|
|
160
|
+
traits: { occupation: 'Kỹ sư' },
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
| Tham số | Kiểu | Mô tả |
|
|
165
|
+
|---|---|---|
|
|
166
|
+
| `profile_id` | `string` | Mặc định lấy profile_id hiện tại |
|
|
167
|
+
| `traits` | `UserTraits` | Các trường cần update |
|
|
168
|
+
| `consents` | `ConsentInfo[]` | Danh sách consent |
|
|
169
|
+
| `scores` | `ScoreInfo[]` | Danh sách điểm |
|
|
170
|
+
| `products` | `ProductInfo[]` | Danh sách sản phẩm |
|
|
171
|
+
| `metadata` | `object` | Thông tin bổ sung |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### Lấy thông tin profile (`getProfile`)
|
|
176
|
+
|
|
177
|
+
Gọi `GET /v1/profiles/get/{profile_id}`.
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Lấy profile hiện tại
|
|
181
|
+
const profile = await cdp.getProfile();
|
|
182
|
+
|
|
183
|
+
// Hoặc chỉ định profile_id cụ thể
|
|
184
|
+
const profile = await cdp.getProfile('cdp_profile_xyz');
|
|
185
|
+
|
|
186
|
+
console.log(profile?.traits);
|
|
187
|
+
console.log(profile?.consents);
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### Trait setters (chainable)
|
|
193
|
+
|
|
194
|
+
Cập nhật từng thuộc tính riêng lẻ. Mỗi setter sẽ tự gọi `POST /v1/profiles/track` với `type: update`. Các setter có thể nối chuỗi.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
cdp
|
|
198
|
+
.add_first_name('Văn A')
|
|
199
|
+
.add_last_name('Nguyễn')
|
|
200
|
+
.add_user_name('Nguyễn Văn A')
|
|
201
|
+
.add_email('user@example.com')
|
|
202
|
+
.add_mobile('0901234567')
|
|
203
|
+
.add_gender('M')
|
|
204
|
+
.add_birthday(new Date('1990-01-15')) // hoặc '1990-01-15'
|
|
205
|
+
.add_idcard('012345678901')
|
|
206
|
+
.add_old_idcard('123456789')
|
|
207
|
+
.add_address('123 Đường ABC, Hà Nội')
|
|
208
|
+
.add_occupation('Kỹ sư phần mềm')
|
|
209
|
+
.add_nationality('Vietnamese')
|
|
210
|
+
.add_marital_status('single')
|
|
211
|
+
.add_religion('Buddhist')
|
|
212
|
+
.add_zalo_id('zalo_123')
|
|
213
|
+
.add_tiktok_id('tiktok_abc');
|
|
214
|
+
|
|
215
|
+
// Cập nhật nhiều thuộc tính cùng lúc
|
|
216
|
+
cdp.add_user_attributes({
|
|
217
|
+
occupation: 'Kỹ sư',
|
|
218
|
+
nationality: 'Vietnamese',
|
|
219
|
+
mps_verified: true,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// Cập nhật một thuộc tính tùy chỉnh
|
|
223
|
+
cdp.add_user_attribute('custom_field', 'value');
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Danh sách trait setters:**
|
|
227
|
+
|
|
228
|
+
| Method | Trường trong `traits` | Ghi chú |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| `add_first_name(v)` | `first_name` | |
|
|
231
|
+
| `add_last_name(v)` | `last_name` | |
|
|
232
|
+
| `add_user_name(v)` | `full_name` | |
|
|
233
|
+
| `add_email(v)` | `email` | PII — tự động mã hoá |
|
|
234
|
+
| `add_mobile(v)` | `phone` | PII — tự động mã hoá |
|
|
235
|
+
| `add_gender(v)` | `gender` | `'M'` \| `'F'` \| `'O'` |
|
|
236
|
+
| `add_birthday(v)` | `dob` | `Date` hoặc `'yyyy-MM-dd'` |
|
|
237
|
+
| `add_idcard(v)` | `idcard` | PII — tự động mã hoá |
|
|
238
|
+
| `add_old_idcard(v)` | `old_idcard` | PII — tự động mã hoá |
|
|
239
|
+
| `add_address(v)` | `address` | PII — tự động mã hoá |
|
|
240
|
+
| `add_occupation(v)` | `occupation` | |
|
|
241
|
+
| `add_nationality(v)` | `nationality` | |
|
|
242
|
+
| `add_marital_status(v)` | `marital_status` | |
|
|
243
|
+
| `add_religion(v)` | `religion` | PII — tự động mã hoá |
|
|
244
|
+
| `add_zalo_id(v)` | `zalo_id` | |
|
|
245
|
+
| `add_tiktok_id(v)` | `tiktok_id` | |
|
|
246
|
+
| `add_user_attribute(name, val)` | tùy chỉnh | |
|
|
247
|
+
| `add_user_attributes(obj)` | nhiều trường | |
|
|
248
|
+
| `setUserAttributes(obj)` | nhiều trường | alias |
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
### Consents
|
|
253
|
+
|
|
254
|
+
Lưu danh sách consent của user. Sẽ được đính kèm vào mọi lần gọi profile sau đó.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
cdp.setConsents([
|
|
258
|
+
{
|
|
259
|
+
consent_type: 'marketing_sms',
|
|
260
|
+
status: true,
|
|
261
|
+
consent_date: '2025-06-01',
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
consent_type: 'marketing_email',
|
|
265
|
+
status: false,
|
|
266
|
+
},
|
|
267
|
+
]);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
| Trường | Kiểu | Bắt buộc | Mô tả |
|
|
271
|
+
|---|---|---|---|
|
|
272
|
+
| `consent_type` | `string` | ✓ | Loại consent |
|
|
273
|
+
| `status` | `boolean` | ✓ | `true` = đồng ý |
|
|
274
|
+
| `consent_date` | `string` | | Ngày đồng ý |
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
### Scores
|
|
279
|
+
|
|
280
|
+
Lưu điểm tín dụng / rủi ro của user.
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
cdp.setScores([
|
|
284
|
+
{
|
|
285
|
+
score_type: 'credit_score',
|
|
286
|
+
score_value: 720,
|
|
287
|
+
score_date: '2025-06-01',
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
score_type: 'risk_score',
|
|
291
|
+
score_value: 85,
|
|
292
|
+
},
|
|
293
|
+
]);
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
| Trường | Kiểu | Bắt buộc | Mô tả |
|
|
297
|
+
|---|---|---|---|
|
|
298
|
+
| `score_type` | `string` | ✓ | Loại điểm |
|
|
299
|
+
| `score_value` | `number` | ✓ | Giá trị |
|
|
300
|
+
| `score_date` | `string` | | Ngày tính điểm |
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
### Products
|
|
305
|
+
|
|
306
|
+
Lưu danh sách sản phẩm mà user đang sử dụng.
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
cdp.setProducts([
|
|
310
|
+
{
|
|
311
|
+
product_code: 'LOAN_CONSUMER',
|
|
312
|
+
product_name: 'Vay tiêu dùng',
|
|
313
|
+
status: 'active',
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
product_code: 'CREDIT_CARD',
|
|
317
|
+
product_name: 'Thẻ tín dụng',
|
|
318
|
+
status: 'pending',
|
|
319
|
+
},
|
|
320
|
+
]);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
| Trường | Kiểu | Bắt buộc | Mô tả |
|
|
324
|
+
|---|---|---|---|
|
|
325
|
+
| `product_code` | `string` | ✓ | Mã sản phẩm |
|
|
326
|
+
| `product_name` | `string` | | Tên sản phẩm |
|
|
327
|
+
| `status` | `string` | | Trạng thái |
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
### Metadata
|
|
332
|
+
|
|
333
|
+
Gắn thêm thông tin tùy chỉnh vào tất cả các payload (profile + event).
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
cdp.setMetadata({
|
|
337
|
+
schema_version: '2.0',
|
|
338
|
+
app_flavor: 'production',
|
|
339
|
+
referral_code: 'REF123',
|
|
340
|
+
});
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
### Campaign / UTM
|
|
346
|
+
|
|
347
|
+
Gắn thông tin chiến dịch vào tất cả event và profile call tiếp theo.
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
cdp.setCampaign({
|
|
351
|
+
utm_source: 'facebook',
|
|
352
|
+
utm_medium: 'cpc',
|
|
353
|
+
utm_campaign: 'summer_loan_2025',
|
|
354
|
+
utm_term: 'vay_tieu_dung',
|
|
355
|
+
utm_content: 'banner_top',
|
|
356
|
+
});
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
### Push Token
|
|
362
|
+
|
|
363
|
+
Lưu FCM token (Android) hoặc APNs token (iOS) để CDP dùng cho push notification.
|
|
364
|
+
|
|
365
|
+
```typescript
|
|
366
|
+
cdp.setPushToken('FCM_OR_APNS_TOKEN_HERE');
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
### Đăng xuất
|
|
372
|
+
|
|
373
|
+
Gửi event logout, xoá toàn bộ dữ liệu user, rotate `anonymous_id` và `session_id`. `device_id` được giữ lại.
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
await cdp.destroy_session();
|
|
377
|
+
|
|
378
|
+
// Alias
|
|
379
|
+
await cdp.reset();
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Sau khi logout:**
|
|
383
|
+
- `userId`, `profileId`, `userTraits`, `consents`, `scores`, `products`, `campaign` → xoá
|
|
384
|
+
- `anonymousId`, `sessionId` → tạo mới
|
|
385
|
+
- `deviceId` → giữ nguyên
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Event Tracking
|
|
390
|
+
|
|
391
|
+
### Track sự kiện
|
|
392
|
+
|
|
393
|
+
```typescript
|
|
394
|
+
cdp.track('button_click', {
|
|
395
|
+
button_name: 'apply_loan',
|
|
396
|
+
screen: 'HomeScreen',
|
|
397
|
+
loan_amount: 50_000_000,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
cdp.track('form_submit', {
|
|
401
|
+
form_name: 'personal_info',
|
|
402
|
+
step: 2,
|
|
403
|
+
duration_seconds: 45,
|
|
404
|
+
});
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
> **Batching:** Events được gom theo `batchSize` hoặc `batchInterval`, sau đó gửi một lần qua `POST /v2/events/batch`. Nếu `batchSize = 1`, mỗi event được gửi ngay qua `POST /v2/events/track`.
|
|
408
|
+
|
|
409
|
+
Mỗi event tự động bao gồm:
|
|
410
|
+
|
|
411
|
+
| Trường | Nguồn |
|
|
412
|
+
|---|---|
|
|
413
|
+
| `event_id` | UUID mới mỗi event |
|
|
414
|
+
| `session_id` | Session hiện tại |
|
|
415
|
+
| `device_id` | Persistent per device |
|
|
416
|
+
| `profile_id` | Từ CDP sau khi login |
|
|
417
|
+
| `anonymous_id` | Persistent, rotate khi logout |
|
|
418
|
+
| `platforms` | Từ `react-native-device-info` |
|
|
419
|
+
| `context.locale` | Ngôn ngữ thiết bị |
|
|
420
|
+
| `context.timezone` | Múi giờ thiết bị |
|
|
421
|
+
| `context.app.version` | Phiên bản app |
|
|
422
|
+
| `event_time` | ISO 8601 tại thời điểm gọi |
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
### Track màn hình (`screen`)
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
cdp.screen('HomeScreen');
|
|
430
|
+
|
|
431
|
+
cdp.screen('LoanDetailScreen', {
|
|
432
|
+
loan_id: 'LOAN_001',
|
|
433
|
+
loan_amount: 50_000_000,
|
|
434
|
+
});
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Tương đương với:
|
|
438
|
+
```typescript
|
|
439
|
+
cdp.track('screen_view', { screen_name: 'HomeScreen', ...properties });
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
---
|
|
443
|
+
|
|
444
|
+
### Flush thủ công
|
|
445
|
+
|
|
446
|
+
Gửi toàn bộ events đang trong queue ngay lập tức. Hữu ích khi app sắp vào background hoặc trước khi đăng xuất.
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
await cdp.flush();
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Lấy thông tin định danh
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
const ids = cdp.getUserIdentities();
|
|
458
|
+
// {
|
|
459
|
+
// user_id: 'user_123',
|
|
460
|
+
// profile_id: 'cdp_abc123',
|
|
461
|
+
// anonymous_id: 'uuid-...',
|
|
462
|
+
// device_id: 'uuid-...',
|
|
463
|
+
// session_id: 'uuid-...',
|
|
464
|
+
// }
|
|
465
|
+
|
|
466
|
+
cdp.getProfileId(); // profile_id từ CDP
|
|
467
|
+
cdp.getDeviceId(); // persistent device identifier
|
|
468
|
+
cdp.getSessionId(); // session hiện tại (mới mỗi lần mở app)
|
|
469
|
+
|
|
470
|
+
cdp.getUserAttribute('phone'); // lấy giá trị trait cụ thể
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
## Bảo mật
|
|
476
|
+
|
|
477
|
+
### HMAC Signature
|
|
478
|
+
|
|
479
|
+
Mọi request tự động được ký. Header `X-Signatures` được tính theo công thức:
|
|
480
|
+
|
|
481
|
+
```
|
|
482
|
+
X-Signatures = Base64(HMAC-SHA256(source + "|" + timestamp + "|" + payload))
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Mã hoá PII (AES-256-CBC)
|
|
486
|
+
|
|
487
|
+
Khi `enableEncryption: true`, các trường nhạy cảm sau được mã hoá trước khi gửi:
|
|
488
|
+
|
|
489
|
+
`full_name`, `first_name`, `last_name`, `phone`, `email`, `idcard`, `old_idcard`, `gender`, `dob`, `address`, `religion`
|
|
490
|
+
|
|
491
|
+
Công thức mã hoá:
|
|
492
|
+
```
|
|
493
|
+
traits = Base64(IV + AES_CBC_PKCS5(key, plaintext_traits_json))
|
|
494
|
+
Key = SHA256(secretKey + X-Timestamp) → 32 bytes (AES-256)
|
|
495
|
+
IV = Random 16 bytes
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Sử dụng thư viện `crypto-js` — pure JavaScript, không cần link native, hoạt động trên cả iOS và Android.
|
|
499
|
+
|
|
500
|
+
---
|
|
501
|
+
|
|
502
|
+
## Dependencies
|
|
503
|
+
|
|
504
|
+
| Package | Lý do |
|
|
505
|
+
|---|---|
|
|
506
|
+
| `@react-native-async-storage/async-storage` | Lưu `device_id`, `anonymous_id`, `profile_id` |
|
|
507
|
+
| `react-native-device-info` | Lấy `brand`, `model`, `os_version`, `app_version` |
|
|
508
|
+
| `crypto-js` | HMAC-SHA256 signature + AES-256-CBC encryption (pure JS) |
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## API Reference
|
|
513
|
+
|
|
514
|
+
### `CdpRnSdk.create(config)`
|
|
515
|
+
|
|
516
|
+
| Tham số | Kiểu | Bắt buộc | Mặc định |
|
|
517
|
+
|---|---|---|---|
|
|
518
|
+
| `apiKey` | `string` | ✓ | |
|
|
519
|
+
| `secretKey` | `string` | ✓ | |
|
|
520
|
+
| `source` | `string` | ✓ | |
|
|
521
|
+
| `serviceName` | `string` | ✓ | |
|
|
522
|
+
| `baseUrl` | `string` | | `https://stg-ingestlog.vietcredit.com.vn` |
|
|
523
|
+
| `isTest` | `boolean` | | `false` |
|
|
524
|
+
| `debug` | `boolean` | | `false` |
|
|
525
|
+
| `batchSize` | `number` | | `10` |
|
|
526
|
+
| `batchInterval` | `number` (ms) | | `5000` |
|
|
527
|
+
| `enableEncryption` | `boolean` | | `true` |
|
|
528
|
+
|
|
529
|
+
### Endpoint mapping
|
|
530
|
+
|
|
531
|
+
| Method SDK | HTTP | Endpoint |
|
|
532
|
+
|---|---|---|
|
|
533
|
+
| `identifyUser()` / `identify()` | POST | `/v1/profiles/track` |
|
|
534
|
+
| `updateProfile()` | POST | `/v1/profiles/update` |
|
|
535
|
+
| `getProfile()` | GET | `/v1/profiles/get/{profile_id}` |
|
|
536
|
+
| `track()` (batchSize=1) | POST | `/v2/events/track` |
|
|
537
|
+
| `track()` / `flush()` (batch) | POST | `/v2/events/batch` |
|
|
538
|
+
| Trait setters | POST | `/v1/profiles/track` (type: update) |
|
|
539
|
+
| `destroy_session()` | POST | `/v1/profiles/track` (type: logout) |
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { CdpRnConfig, UserTraits, PlatformInfo, CampaignInfo, ConsentInfo, ScoreInfo, ProductInfo, EventProperties, ProfileUpdatePayload, ProfileResponse, ProfileData, UserIdentities, PartyType } from './types';
|
|
2
|
+
export declare class CdpRnSdk {
|
|
3
|
+
private config;
|
|
4
|
+
private userId;
|
|
5
|
+
private profileId;
|
|
6
|
+
private anonymousId;
|
|
7
|
+
private deviceId;
|
|
8
|
+
private sessionId;
|
|
9
|
+
private userTraits;
|
|
10
|
+
private platforms;
|
|
11
|
+
private campaign;
|
|
12
|
+
private consents;
|
|
13
|
+
private scores;
|
|
14
|
+
private products;
|
|
15
|
+
private metadata;
|
|
16
|
+
private eventQueue;
|
|
17
|
+
private preInitQueue;
|
|
18
|
+
private batchTimer;
|
|
19
|
+
private initialized;
|
|
20
|
+
private constructor();
|
|
21
|
+
/**
|
|
22
|
+
* Create and initialize the SDK. Call once at app startup (e.g. App.tsx).
|
|
23
|
+
*/
|
|
24
|
+
static create(config: CdpRnConfig): Promise<CdpRnSdk>;
|
|
25
|
+
private _init;
|
|
26
|
+
/**
|
|
27
|
+
* Identify user after login. Calls POST /v1/profiles/track and stores profile_id.
|
|
28
|
+
* @param partyType defaults to 'PERSON', pass 'ORG' for business accounts
|
|
29
|
+
*/
|
|
30
|
+
identifyUser(userId: string, traits?: UserTraits, partyType?: PartyType): Promise<this>;
|
|
31
|
+
/** Alias for identifyUser */
|
|
32
|
+
identify(userId: string, traits?: UserTraits, partyType?: PartyType): Promise<this>;
|
|
33
|
+
/**
|
|
34
|
+
* Force-update profile by profile_id. Calls POST /v1/profiles/update.
|
|
35
|
+
* Use when you need to push specific field changes without triggering identity resolution.
|
|
36
|
+
*/
|
|
37
|
+
updateProfile(payload: Omit<ProfileUpdatePayload, 'profile_id'> & {
|
|
38
|
+
profile_id?: string;
|
|
39
|
+
}): Promise<ProfileResponse | undefined>;
|
|
40
|
+
/**
|
|
41
|
+
* Fetch profile data from CDP. Calls GET /v1/profiles/get/{profile_id}.
|
|
42
|
+
*/
|
|
43
|
+
getProfile(profileId?: string): Promise<ProfileData | undefined>;
|
|
44
|
+
getUserIdentities(): UserIdentities;
|
|
45
|
+
getProfileId(): string | null;
|
|
46
|
+
getDeviceId(): string;
|
|
47
|
+
getSessionId(): string;
|
|
48
|
+
getUserAttribute(name: keyof UserTraits): unknown;
|
|
49
|
+
add_first_name(v: string): this;
|
|
50
|
+
add_last_name(v: string): this;
|
|
51
|
+
add_user_name(v: string): this;
|
|
52
|
+
add_email(v: string): this;
|
|
53
|
+
add_mobile(v: string): this;
|
|
54
|
+
add_gender(v: 'M' | 'F' | 'O'): this;
|
|
55
|
+
add_idcard(v: string): this;
|
|
56
|
+
add_old_idcard(v: string): this;
|
|
57
|
+
add_address(v: string): this;
|
|
58
|
+
add_religion(v: string): this;
|
|
59
|
+
add_occupation(v: string): this;
|
|
60
|
+
add_nationality(v: string): this;
|
|
61
|
+
add_marital_status(v: string): this;
|
|
62
|
+
add_zalo_id(v: string): this;
|
|
63
|
+
add_tiktok_id(v: string): this;
|
|
64
|
+
add_birthday(birthday: Date | string): this;
|
|
65
|
+
add_user_attribute(name: string, value: unknown): this;
|
|
66
|
+
add_user_attributes(attributes: UserTraits): this;
|
|
67
|
+
setUserAttributes(attributes: UserTraits): this;
|
|
68
|
+
/**
|
|
69
|
+
* Set user consents (e.g. marketing opt-in).
|
|
70
|
+
* These are included in every subsequent profile call.
|
|
71
|
+
*/
|
|
72
|
+
setConsents(consents: ConsentInfo[]): this;
|
|
73
|
+
/**
|
|
74
|
+
* Set user scores (credit score, risk score, etc.).
|
|
75
|
+
*/
|
|
76
|
+
setScores(scores: ScoreInfo[]): this;
|
|
77
|
+
/**
|
|
78
|
+
* Set user associated products (loan, card, etc.).
|
|
79
|
+
*/
|
|
80
|
+
setProducts(products: ProductInfo[]): this;
|
|
81
|
+
/**
|
|
82
|
+
* Set extra metadata to include in profile and event payloads.
|
|
83
|
+
*/
|
|
84
|
+
setMetadata(meta: Record<string, unknown>): this;
|
|
85
|
+
setPlatform(info: PlatformInfo): this;
|
|
86
|
+
setCampaign(info: CampaignInfo): this;
|
|
87
|
+
/**
|
|
88
|
+
* Store FCM (Android) or APNs (iOS) push token for push notification targeting.
|
|
89
|
+
*/
|
|
90
|
+
setPushToken(token: string): this;
|
|
91
|
+
/**
|
|
92
|
+
* Track a custom event.
|
|
93
|
+
*/
|
|
94
|
+
track(eventName: string, properties?: EventProperties): void;
|
|
95
|
+
/**
|
|
96
|
+
* Track a screen view — React Native equivalent of page().
|
|
97
|
+
*/
|
|
98
|
+
screen(screenName: string, properties?: EventProperties): void;
|
|
99
|
+
/**
|
|
100
|
+
* Flush queued events to the server immediately.
|
|
101
|
+
*/
|
|
102
|
+
flush(): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Logout: sends a logout profile event and resets all user state.
|
|
105
|
+
* anonymous_id is rotated; device_id is kept.
|
|
106
|
+
*/
|
|
107
|
+
destroy_session(): Promise<this>;
|
|
108
|
+
/** Alias for destroy_session */
|
|
109
|
+
reset(): Promise<this>;
|
|
110
|
+
destroy(): Promise<void>;
|
|
111
|
+
private _trackProfile;
|
|
112
|
+
private _createEvent;
|
|
113
|
+
private _enqueueOrSend;
|
|
114
|
+
private _sendEvent;
|
|
115
|
+
private _sendBatch;
|
|
116
|
+
private _addToQueue;
|
|
117
|
+
private _startBatchProcessor;
|
|
118
|
+
private _buildHeaders;
|
|
119
|
+
private _request;
|
|
120
|
+
private _requestGet;
|
|
121
|
+
private _setTrait;
|
|
122
|
+
private _extractSensitiveTraits;
|
|
123
|
+
private _getOrCreate;
|
|
124
|
+
private _getLocale;
|
|
125
|
+
private _getTimezone;
|
|
126
|
+
private _log;
|
|
127
|
+
private _logError;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=CdpRnSdk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CdpRnSdk.d.ts","sourceRoot":"","sources":["../src/CdpRnSdk.ts"],"names":[],"mappings":"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"}
|