vc-cdp-rn-sdk 0.1.1 → 0.1.2
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 +598 -324
- package/docs/getting-started.md +5 -5
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -10,24 +10,28 @@ CDP SDK cho React Native — tracking events và user profiles cho hệ thống
|
|
|
10
10
|
- [Khởi tạo](#khởi-tạo)
|
|
11
11
|
- [Luồng hoạt động](#luồng-hoạt-động)
|
|
12
12
|
- [User / Profile](#user--profile)
|
|
13
|
-
- [
|
|
14
|
-
- [
|
|
15
|
-
- [
|
|
16
|
-
- [
|
|
13
|
+
- [identifyUser](#identifyuser--đăng-nhập)
|
|
14
|
+
- [Trait Setters](#trait-setters--cập-nhật-từng-thuộc-tính)
|
|
15
|
+
- [updateProfile](#updateprofile--force-update)
|
|
16
|
+
- [getProfile](#getprofile--lấy-thông-tin-profile)
|
|
17
17
|
- [Consents](#consents)
|
|
18
18
|
- [Scores](#scores)
|
|
19
19
|
- [Products](#products)
|
|
20
|
-
- [Metadata](#metadata)
|
|
21
|
-
- [
|
|
22
|
-
- [
|
|
23
|
-
- [Đăng xuất](#đăng-xuất)
|
|
20
|
+
- [Metadata, Campaign, Push Token](#metadata-campaign-push-token)
|
|
21
|
+
- [getUserIdentities](#getuseridentities)
|
|
22
|
+
- [destroy_session](#destroy_session--đăng-xuất)
|
|
24
23
|
- [Event Tracking](#event-tracking)
|
|
25
|
-
- [
|
|
26
|
-
- [
|
|
27
|
-
- [
|
|
28
|
-
- [
|
|
24
|
+
- [track](#track--custom-event)
|
|
25
|
+
- [screen](#screen--màn-hình)
|
|
26
|
+
- [React Navigation](#tích-hợp-react-navigation)
|
|
27
|
+
- [Batch Processing](#batch-processing)
|
|
28
|
+
- [flush](#flush--gửi-ngay)
|
|
29
|
+
- [destroy](#destroy--dọn-dẹp)
|
|
29
30
|
- [Bảo mật](#bảo-mật)
|
|
30
|
-
- [
|
|
31
|
+
- [HMAC-SHA256](#hmac-sha256-signature)
|
|
32
|
+
- [AES-256-CBC](#aes-256-cbc-encryption)
|
|
33
|
+
- [Best Practices](#best-practices)
|
|
34
|
+
- [Tích hợp React Navigation đầy đủ](#tích-hợp-react-navigation-đầy-đủ)
|
|
31
35
|
- [API Reference](#api-reference)
|
|
32
36
|
|
|
33
37
|
---
|
|
@@ -35,49 +39,92 @@ CDP SDK cho React Native — tracking events và user profiles cho hệ thống
|
|
|
35
39
|
## Cài đặt
|
|
36
40
|
|
|
37
41
|
```bash
|
|
38
|
-
npm install vc-cdp-rn-sdk
|
|
42
|
+
npm install vc-cdp-rn-sdk
|
|
39
43
|
```
|
|
40
44
|
|
|
41
|
-
###
|
|
45
|
+
### Peer Dependencies
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @react-native-async-storage/async-storage
|
|
49
|
+
npm install react-native-device-info
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### iOS
|
|
42
53
|
|
|
43
54
|
```bash
|
|
44
55
|
cd ios && pod install
|
|
45
56
|
```
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
#### Android
|
|
48
59
|
|
|
49
|
-
Không cần
|
|
60
|
+
Không cần thêm cấu hình nếu dùng React Native >= 0.68 (auto-linking).
|
|
50
61
|
|
|
51
62
|
---
|
|
52
63
|
|
|
53
64
|
## Khởi tạo
|
|
54
65
|
|
|
55
|
-
|
|
66
|
+
Khởi tạo SDK **một lần duy nhất** tại entry point của app. SDK dùng `AsyncStorage` nên init là **async**.
|
|
56
67
|
|
|
57
68
|
```typescript
|
|
69
|
+
// src/lib/cdp.ts
|
|
58
70
|
import { CdpRnSdk } from 'vc-cdp-rn-sdk';
|
|
59
71
|
|
|
60
|
-
let
|
|
61
|
-
|
|
62
|
-
export async function
|
|
63
|
-
|
|
64
|
-
apiKey:
|
|
65
|
-
secretKey:
|
|
66
|
-
source:
|
|
67
|
-
serviceName: '
|
|
68
|
-
|
|
69
|
-
|
|
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)
|
|
72
|
+
let _cdp: CdpRnSdk | null = null;
|
|
73
|
+
|
|
74
|
+
export async function initCdp(): Promise<CdpRnSdk> {
|
|
75
|
+
_cdp = await CdpRnSdk.create({
|
|
76
|
+
apiKey: 'YOUR_API_KEY',
|
|
77
|
+
secretKey: 'YOUR_SECRET_KEY',
|
|
78
|
+
source: 'DOP',
|
|
79
|
+
serviceName: 'VC_APP',
|
|
80
|
+
baseUrl: 'https://ingestlog.vietcredit.com.vn',
|
|
81
|
+
debug: __DEV__,
|
|
76
82
|
});
|
|
83
|
+
return _cdp;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function getCdp(): CdpRnSdk {
|
|
87
|
+
if (!_cdp) throw new Error('CDP SDK chưa được khởi tạo. Gọi initCdp() trước.');
|
|
88
|
+
return _cdp;
|
|
77
89
|
}
|
|
78
90
|
```
|
|
79
91
|
|
|
80
|
-
|
|
92
|
+
```typescript
|
|
93
|
+
// App.tsx
|
|
94
|
+
import { useEffect } from 'react';
|
|
95
|
+
import { initCdp } from './lib/cdp';
|
|
96
|
+
|
|
97
|
+
export default function App() {
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
initCdp();
|
|
100
|
+
}, []);
|
|
101
|
+
// ...
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
> **Lưu ý:** Mỗi lần `CdpRnSdk.create()` được gọi, SDK tự động tạo `session_id` mới — tương ứng với 1 lần mở app.
|
|
106
|
+
|
|
107
|
+
### Cấu hình đầy đủ
|
|
108
|
+
|
|
109
|
+
| Tham số | Kiểu | Mặc định | Mô tả |
|
|
110
|
+
|---|---|---|---|
|
|
111
|
+
| `apiKey` | `string` | — | **Bắt buộc.** API Key do CDP cấp |
|
|
112
|
+
| `secretKey` | `string` | — | **Bắt buộc.** Secret Key để ký HMAC và mã hoá AES |
|
|
113
|
+
| `source` | `string` | — | **Bắt buộc.** Kênh tích hợp (khai báo với CDP trước) |
|
|
114
|
+
| `serviceName` | `string` | — | **Bắt buộc.** `VC_APP` \| `DOP` \| `LOS` \| `LMS` |
|
|
115
|
+
| `baseUrl` | `string` | Staging URL | URL API CDP (không có `/v1`) |
|
|
116
|
+
| `isTest` | `boolean` | `false` | Đánh dấu môi trường test |
|
|
117
|
+
| `debug` | `boolean` | `false` | In log ra console |
|
|
118
|
+
| `batchSize` | `number` | `10` | Số events tối đa trong 1 batch |
|
|
119
|
+
| `batchInterval` | `number` | `5000` | Thời gian (ms) giữa các lần flush tự động |
|
|
120
|
+
| `enableEncryption` | `boolean` | `true` | Mã hoá PII bằng AES-256-CBC |
|
|
121
|
+
|
|
122
|
+
### Môi trường
|
|
123
|
+
|
|
124
|
+
| Môi trường | baseUrl |
|
|
125
|
+
|---|---|
|
|
126
|
+
| Staging | `https://stg-ingestlog.vietcredit.com.vn` |
|
|
127
|
+
| Production | `https://ingestlog.vietcredit.com.vn` |
|
|
81
128
|
|
|
82
129
|
---
|
|
83
130
|
|
|
@@ -85,113 +132,77 @@ export async function setupCdp() {
|
|
|
85
132
|
|
|
86
133
|
```
|
|
87
134
|
App khởi động
|
|
88
|
-
└─> CdpRnSdk.create(config)
|
|
89
|
-
│ -
|
|
90
|
-
│ - Load anonymous_id
|
|
91
|
-
│ -
|
|
92
|
-
│ -
|
|
135
|
+
└─> CdpRnSdk.create(config) ← async
|
|
136
|
+
│ - Load/tạo device_id → AsyncStorage (persist vĩnh viễn)
|
|
137
|
+
│ - Load/tạo anonymous_id → AsyncStorage (persist vĩnh viễn)
|
|
138
|
+
│ - Tạo session_id mới → AsyncStorage (mỗi lần mở app)
|
|
139
|
+
│ - Load profile_id → AsyncStorage (nếu đã login)
|
|
93
140
|
│
|
|
94
141
|
├─ User CHƯA login
|
|
95
|
-
│ └─> cdp.track(
|
|
142
|
+
│ └─> cdp.track() / cdp.screen()
|
|
96
143
|
│ profile_id = null, gắn anonymous_id + device_id + session_id
|
|
97
|
-
│ CDP sẽ identity-resolve khi user login sau
|
|
98
144
|
│
|
|
99
145
|
└─ User login
|
|
100
146
|
└─> cdp.identifyUser(userId, traits)
|
|
101
147
|
└─> 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
|
|
148
|
+
└─> cdp.track() gắn profile_id vào mọi event
|
|
104
149
|
```
|
|
105
150
|
|
|
106
|
-
**
|
|
151
|
+
**Storage scope (AsyncStorage):**
|
|
152
|
+
|
|
153
|
+
| | Vòng đời |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `device_id` | Vĩnh viễn (đến khi xoá app) |
|
|
156
|
+
| `anonymous_id` | Vĩnh viễn (rotate khi logout) |
|
|
157
|
+
| `session_id` | Tạo mới mỗi lần `create()` |
|
|
158
|
+
| `profile_id` | Xoá khi `destroy_session()` |
|
|
107
159
|
|
|
108
160
|
---
|
|
109
161
|
|
|
110
162
|
## User / Profile
|
|
111
163
|
|
|
112
|
-
### Đăng nhập
|
|
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.
|
|
164
|
+
### identifyUser — Đăng nhập
|
|
115
165
|
|
|
116
166
|
```typescript
|
|
117
|
-
await cdp.identifyUser(
|
|
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' });
|
|
167
|
+
await cdp.identifyUser(userId, traits?, partyType?)
|
|
130
168
|
```
|
|
131
169
|
|
|
132
170
|
| Tham số | Kiểu | Bắt buộc | Mô tả |
|
|
133
171
|
|---|---|---|---|
|
|
134
|
-
| `userId` | `string` | ✓ | Mã user trong hệ thống |
|
|
172
|
+
| `userId` | `string` | ✓ | Mã user trong hệ thống nội bộ |
|
|
135
173
|
| `traits` | `UserTraits` | | Thông tin nhân khẩu học |
|
|
136
174
|
| `partyType` | `'PERSON' \| 'ORG'` | | Mặc định `'PERSON'` |
|
|
137
175
|
|
|
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
176
|
```typescript
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
177
|
+
// Cá nhân
|
|
178
|
+
await cdp.identifyUser('user_001', {
|
|
179
|
+
phone: '0901234567',
|
|
180
|
+
email: 'user@example.com',
|
|
181
|
+
full_name: 'Nguyễn Văn A',
|
|
182
|
+
gender: 'M',
|
|
183
|
+
dob: '1990-01-15',
|
|
184
|
+
idcard: '012345678901',
|
|
185
|
+
address: '123 Lê Lợi, Q.1, TP.HCM',
|
|
186
|
+
occupation: 'Kỹ sư phần mềm',
|
|
187
|
+
nationality: 'Vietnamese',
|
|
188
|
+
marital_status: 'single',
|
|
155
189
|
});
|
|
156
190
|
|
|
157
|
-
|
|
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');
|
|
191
|
+
console.log(cdp.getProfileId()); // → "177671850461184000"
|
|
185
192
|
|
|
186
|
-
|
|
187
|
-
|
|
193
|
+
// Tổ chức
|
|
194
|
+
await cdp.identifyUser('org_001', {
|
|
195
|
+
full_name: 'Công ty TNHH ABC',
|
|
196
|
+
phone: '0281234567',
|
|
197
|
+
email: 'contact@abc.vn',
|
|
198
|
+
}, 'ORG');
|
|
188
199
|
```
|
|
189
200
|
|
|
190
201
|
---
|
|
191
202
|
|
|
192
|
-
### Trait
|
|
203
|
+
### Trait Setters — Cập nhật từng thuộc tính
|
|
193
204
|
|
|
194
|
-
|
|
205
|
+
Chainable. Mỗi setter gọi ngay `POST /v1/profiles/track` (type: update).
|
|
195
206
|
|
|
196
207
|
```typescript
|
|
197
208
|
cdp
|
|
@@ -201,352 +212,615 @@ cdp
|
|
|
201
212
|
.add_email('user@example.com')
|
|
202
213
|
.add_mobile('0901234567')
|
|
203
214
|
.add_gender('M')
|
|
204
|
-
.add_birthday(
|
|
215
|
+
.add_birthday('1990-01-15')
|
|
205
216
|
.add_idcard('012345678901')
|
|
206
217
|
.add_old_idcard('123456789')
|
|
207
|
-
.add_address('123
|
|
218
|
+
.add_address('123 Lê Lợi, Q.1, TP.HCM')
|
|
208
219
|
.add_occupation('Kỹ sư phần mềm')
|
|
209
220
|
.add_nationality('Vietnamese')
|
|
210
221
|
.add_marital_status('single')
|
|
211
222
|
.add_religion('Buddhist')
|
|
212
|
-
.add_zalo_id('
|
|
213
|
-
.add_tiktok_id('
|
|
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');
|
|
223
|
+
.add_zalo_id('zalo_user_001')
|
|
224
|
+
.add_tiktok_id('tiktok_user_001');
|
|
224
225
|
```
|
|
225
226
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
| Method | Trường trong `traits` | Ghi chú |
|
|
227
|
+
| Method | Trường | Ghi chú |
|
|
229
228
|
|---|---|---|
|
|
230
229
|
| `add_first_name(v)` | `first_name` | |
|
|
231
230
|
| `add_last_name(v)` | `last_name` | |
|
|
232
231
|
| `add_user_name(v)` | `full_name` | |
|
|
233
|
-
| `add_email(v)` | `email` | PII
|
|
234
|
-
| `add_mobile(v)` | `phone` | PII
|
|
232
|
+
| `add_email(v)` | `email` | 🔒 PII |
|
|
233
|
+
| `add_mobile(v)` | `phone` | 🔒 PII |
|
|
235
234
|
| `add_gender(v)` | `gender` | `'M'` \| `'F'` \| `'O'` |
|
|
236
235
|
| `add_birthday(v)` | `dob` | `Date` hoặc `'yyyy-MM-dd'` |
|
|
237
|
-
| `add_idcard(v)` | `idcard` | PII
|
|
238
|
-
| `add_old_idcard(v)` | `old_idcard` | PII
|
|
239
|
-
| `add_address(v)` | `address` | PII
|
|
236
|
+
| `add_idcard(v)` | `idcard` | 🔒 PII |
|
|
237
|
+
| `add_old_idcard(v)` | `old_idcard` | 🔒 PII |
|
|
238
|
+
| `add_address(v)` | `address` | 🔒 PII |
|
|
240
239
|
| `add_occupation(v)` | `occupation` | |
|
|
241
240
|
| `add_nationality(v)` | `nationality` | |
|
|
242
241
|
| `add_marital_status(v)` | `marital_status` | |
|
|
243
|
-
| `add_religion(v)` | `religion` | PII
|
|
242
|
+
| `add_religion(v)` | `religion` | 🔒 PII |
|
|
244
243
|
| `add_zalo_id(v)` | `zalo_id` | |
|
|
245
244
|
| `add_tiktok_id(v)` | `tiktok_id` | |
|
|
246
|
-
| `add_user_attribute(name, val)` |
|
|
247
|
-
| `add_user_attributes(obj)` | nhiều trường | |
|
|
248
|
-
| `setUserAttributes(obj)` | nhiều trường |
|
|
245
|
+
| `add_user_attribute(name, val)` | custom | Bất kỳ trường nào |
|
|
246
|
+
| `add_user_attributes(obj)` | nhiều trường | Batch update |
|
|
247
|
+
| `setUserAttributes(obj)` | nhiều trường | Alias |
|
|
249
248
|
|
|
250
249
|
---
|
|
251
250
|
|
|
252
|
-
###
|
|
251
|
+
### updateProfile — Force-update
|
|
253
252
|
|
|
254
|
-
|
|
253
|
+
```typescript
|
|
254
|
+
await cdp.updateProfile({
|
|
255
|
+
traits: { kyc_status: 'verified', mps_verified: true },
|
|
256
|
+
consents: [{ consent_type: 'marketing_sms', status: true, consent_date: '2025-06-01' }],
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### getProfile — Lấy thông tin profile
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
const profile = await cdp.getProfile();
|
|
266
|
+
const profile = await cdp.getProfile('cdp_123');
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
### Consents
|
|
255
272
|
|
|
256
273
|
```typescript
|
|
257
274
|
cdp.setConsents([
|
|
258
|
-
{
|
|
259
|
-
|
|
260
|
-
status: true,
|
|
261
|
-
consent_date: '2025-06-01',
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
consent_type: 'marketing_email',
|
|
265
|
-
status: false,
|
|
266
|
-
},
|
|
275
|
+
{ consent_type: 'marketing_sms', status: true, consent_date: '2025-06-01' },
|
|
276
|
+
{ consent_type: 'marketing_email', status: false },
|
|
277
|
+
{ consent_type: 'data_sharing', status: true },
|
|
267
278
|
]);
|
|
268
279
|
```
|
|
269
280
|
|
|
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
281
|
---
|
|
277
282
|
|
|
278
283
|
### Scores
|
|
279
284
|
|
|
280
|
-
Lưu điểm tín dụng / rủi ro của user.
|
|
281
|
-
|
|
282
285
|
```typescript
|
|
283
286
|
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
|
-
},
|
|
287
|
+
{ score_type: 'credit_score', score_value: 720, score_date: '2025-06-01' },
|
|
293
288
|
]);
|
|
294
289
|
```
|
|
295
290
|
|
|
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
291
|
---
|
|
303
292
|
|
|
304
293
|
### Products
|
|
305
294
|
|
|
306
|
-
Lưu danh sách sản phẩm mà user đang sử dụng.
|
|
307
|
-
|
|
308
295
|
```typescript
|
|
309
296
|
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
|
-
},
|
|
297
|
+
{ product_code: 'LOAN_CONSUMER', product_name: 'Vay tiêu dùng', status: 'active' },
|
|
320
298
|
]);
|
|
321
299
|
```
|
|
322
300
|
|
|
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
301
|
---
|
|
330
302
|
|
|
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).
|
|
303
|
+
### Metadata, Campaign, Push Token
|
|
334
304
|
|
|
335
305
|
```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
|
|
306
|
+
cdp.setMetadata({ schema_version: '2.0', referral_code: 'REF123' });
|
|
346
307
|
|
|
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
308
|
cdp.setCampaign({
|
|
351
|
-
utm_source:
|
|
352
|
-
utm_medium:
|
|
309
|
+
utm_source: 'facebook',
|
|
310
|
+
utm_medium: 'cpc',
|
|
353
311
|
utm_campaign: 'summer_loan_2025',
|
|
354
|
-
utm_term: 'vay_tieu_dung',
|
|
355
|
-
utm_content: 'banner_top',
|
|
356
312
|
});
|
|
313
|
+
|
|
314
|
+
// Push notification token (Expo hoặc FCM)
|
|
315
|
+
cdp.setPushToken('ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]');
|
|
316
|
+
cdp.setPushToken('fcm_token_abc123...');
|
|
357
317
|
```
|
|
358
318
|
|
|
359
319
|
---
|
|
360
320
|
|
|
361
|
-
###
|
|
362
|
-
|
|
363
|
-
Lưu FCM token (Android) hoặc APNs token (iOS) để CDP dùng cho push notification.
|
|
321
|
+
### getUserIdentities
|
|
364
322
|
|
|
365
323
|
```typescript
|
|
366
|
-
cdp.
|
|
324
|
+
const ids = cdp.getUserIdentities();
|
|
325
|
+
// {
|
|
326
|
+
// user_id: 'user_001',
|
|
327
|
+
// profile_id: '177671850461184000',
|
|
328
|
+
// anonymous_id: 'uuid-...',
|
|
329
|
+
// device_id: 'uuid-...',
|
|
330
|
+
// session_id: 'uuid-...',
|
|
331
|
+
// }
|
|
332
|
+
|
|
333
|
+
cdp.getProfileId();
|
|
334
|
+
cdp.getDeviceId();
|
|
335
|
+
cdp.getSessionId();
|
|
336
|
+
cdp.getUserAttribute('phone');
|
|
367
337
|
```
|
|
368
338
|
|
|
369
339
|
---
|
|
370
340
|
|
|
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.
|
|
341
|
+
### destroy_session — Đăng xuất
|
|
374
342
|
|
|
375
343
|
```typescript
|
|
376
344
|
await cdp.destroy_session();
|
|
377
|
-
|
|
378
|
-
// Alias
|
|
345
|
+
// hoặc alias:
|
|
379
346
|
await cdp.reset();
|
|
380
347
|
```
|
|
381
348
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
349
|
+
| | Hành động |
|
|
350
|
+
|---|---|
|
|
351
|
+
| `userId`, `profileId`, `userTraits` | Xoá |
|
|
352
|
+
| `consents`, `scores`, `products`, `campaign` | Xoá |
|
|
353
|
+
| `anonymous_id` | Tạo mới, lưu AsyncStorage |
|
|
354
|
+
| `session_id` | Tạo mới, lưu AsyncStorage |
|
|
355
|
+
| `device_id` | **Giữ nguyên** |
|
|
386
356
|
|
|
387
357
|
---
|
|
388
358
|
|
|
389
359
|
## Event Tracking
|
|
390
360
|
|
|
391
|
-
###
|
|
361
|
+
### track — Custom event
|
|
392
362
|
|
|
393
363
|
```typescript
|
|
394
|
-
cdp.track(
|
|
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
|
-
});
|
|
364
|
+
cdp.track(eventName, properties?)
|
|
405
365
|
```
|
|
406
366
|
|
|
407
|
-
|
|
367
|
+
```typescript
|
|
368
|
+
cdp.track('loan_viewed', {
|
|
369
|
+
loan_id: 'LOAN_001',
|
|
370
|
+
amount: 50_000_000,
|
|
371
|
+
term: 24,
|
|
372
|
+
type: 'consumer',
|
|
373
|
+
});
|
|
408
374
|
|
|
409
|
-
|
|
375
|
+
cdp.track('button_click', { button: 'apply_now', screen: 'LoanDetailScreen' });
|
|
410
376
|
|
|
411
|
-
|
|
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 |
|
|
377
|
+
cdp.track('form_submitted', { form: 'loan_application', success: true });
|
|
378
|
+
```
|
|
423
379
|
|
|
424
380
|
---
|
|
425
381
|
|
|
426
|
-
###
|
|
382
|
+
### screen — Màn hình
|
|
383
|
+
|
|
384
|
+
Track lượt xem màn hình. Gửi event `screen_view`.
|
|
427
385
|
|
|
428
386
|
```typescript
|
|
429
387
|
cdp.screen('HomeScreen');
|
|
430
|
-
|
|
431
|
-
cdp.screen('
|
|
432
|
-
loan_id: 'LOAN_001',
|
|
433
|
-
loan_amount: 50_000_000,
|
|
434
|
-
});
|
|
388
|
+
cdp.screen('LoanDetailScreen', { loan_code: 'CONSUMER_24M' });
|
|
389
|
+
cdp.screen('ProfileScreen', { tab: 'personal_info' });
|
|
435
390
|
```
|
|
436
391
|
|
|
437
|
-
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
### Tích hợp React Navigation
|
|
395
|
+
|
|
438
396
|
```typescript
|
|
439
|
-
|
|
397
|
+
// App.tsx
|
|
398
|
+
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
|
|
399
|
+
import { getCdp } from './lib/cdp';
|
|
400
|
+
|
|
401
|
+
export default function App() {
|
|
402
|
+
const navRef = useNavigationContainerRef();
|
|
403
|
+
|
|
404
|
+
return (
|
|
405
|
+
<NavigationContainer
|
|
406
|
+
ref={navRef}
|
|
407
|
+
onReady={() => {
|
|
408
|
+
const name = navRef.getCurrentRoute()?.name;
|
|
409
|
+
if (name) getCdp().screen(name);
|
|
410
|
+
}}
|
|
411
|
+
onStateChange={() => {
|
|
412
|
+
const name = navRef.getCurrentRoute()?.name;
|
|
413
|
+
if (name) getCdp().screen(name);
|
|
414
|
+
}}
|
|
415
|
+
>
|
|
416
|
+
{/* Stack / Tab / Drawer navigators */}
|
|
417
|
+
</NavigationContainer>
|
|
418
|
+
);
|
|
419
|
+
}
|
|
440
420
|
```
|
|
441
421
|
|
|
442
422
|
---
|
|
443
423
|
|
|
444
|
-
###
|
|
424
|
+
### Batch Processing
|
|
425
|
+
|
|
426
|
+
Events được gom vào **queue** rồi flush theo điều kiện:
|
|
427
|
+
|
|
428
|
+
| Điều kiện | Mô tả |
|
|
429
|
+
|---|---|
|
|
430
|
+
| `batchSize` đạt ngưỡng | Mặc định 10 events |
|
|
431
|
+
| `batchInterval` timeout | Mặc định 5 000 ms |
|
|
432
|
+
| `flush()` gọi thủ công | Ngay lập tức |
|
|
433
|
+
| App vào background | Gọi `flush()` trước `AppState` change |
|
|
434
|
+
|
|
435
|
+
---
|
|
445
436
|
|
|
446
|
-
|
|
437
|
+
### flush — Gửi ngay
|
|
447
438
|
|
|
448
439
|
```typescript
|
|
449
440
|
await cdp.flush();
|
|
450
441
|
```
|
|
451
442
|
|
|
452
|
-
|
|
443
|
+
```typescript
|
|
444
|
+
// Flush khi app vào background
|
|
445
|
+
import { AppState } from 'react-native';
|
|
453
446
|
|
|
454
|
-
|
|
447
|
+
AppState.addEventListener('change', async (state) => {
|
|
448
|
+
if (state === 'background') {
|
|
449
|
+
await cdp.flush();
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
```
|
|
455
453
|
|
|
456
|
-
|
|
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
|
-
// }
|
|
454
|
+
---
|
|
465
455
|
|
|
466
|
-
|
|
467
|
-
cdp.getDeviceId(); // persistent device identifier
|
|
468
|
-
cdp.getSessionId(); // session hiện tại (mới mỗi lần mở app)
|
|
456
|
+
### destroy — Dọn dẹp
|
|
469
457
|
|
|
470
|
-
|
|
458
|
+
```typescript
|
|
459
|
+
await cdp.destroy();
|
|
471
460
|
```
|
|
472
461
|
|
|
462
|
+
Flush queue còn lại và xoá timer. Không xoá user data.
|
|
463
|
+
|
|
473
464
|
---
|
|
474
465
|
|
|
475
466
|
## Bảo mật
|
|
476
467
|
|
|
477
|
-
### HMAC Signature
|
|
468
|
+
### HMAC-SHA256 Signature
|
|
469
|
+
|
|
470
|
+
Mọi request đến CDP API đều được ký tự động.
|
|
478
471
|
|
|
479
|
-
|
|
472
|
+
**Headers:**
|
|
480
473
|
|
|
481
474
|
```
|
|
482
|
-
X-
|
|
475
|
+
X-Api-Key: <apiKey>
|
|
476
|
+
X-Source: <source>
|
|
477
|
+
X-Timestamp: <unix_timestamp_s>
|
|
478
|
+
X-Signatures: <base64_signature>
|
|
479
|
+
X-Trace-Id: <uuid>
|
|
480
|
+
Content-Type: application/json
|
|
481
|
+
isTest: false
|
|
483
482
|
```
|
|
484
483
|
|
|
485
|
-
|
|
484
|
+
**Công thức:**
|
|
486
485
|
|
|
487
|
-
|
|
486
|
+
```
|
|
487
|
+
signature = Base64( HMAC-SHA256(secretKey, message) )
|
|
488
|
+
message = source + "|" + timestamp + "|" + JSON(payload)
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
> **Lưu ý:** RN SDK dùng timestamp tính bằng **giây** (khác với Web SDK dùng milliseconds).
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
### AES-256-CBC Encryption
|
|
496
|
+
|
|
497
|
+
Khi `enableEncryption: true`, các trường PII được mã hoá.
|
|
488
498
|
|
|
489
|
-
|
|
499
|
+
**Các trường PII bị mã hoá:**
|
|
500
|
+
|
|
501
|
+
| Trường | Mô tả |
|
|
502
|
+
|---|---|
|
|
503
|
+
| `phone` | Số điện thoại |
|
|
504
|
+
| `email` | Email |
|
|
505
|
+
| `idcard` | CMND/CCCD mới |
|
|
506
|
+
| `old_idcard` | CMND cũ |
|
|
507
|
+
| `address` | Địa chỉ |
|
|
508
|
+
| `religion` | Tôn giáo |
|
|
509
|
+
| `full_name` | Họ tên đầy đủ |
|
|
510
|
+
| `first_name` | Tên |
|
|
511
|
+
| `last_name` | Họ |
|
|
512
|
+
| `gender` | Giới tính |
|
|
513
|
+
| `dob` | Ngày sinh |
|
|
514
|
+
|
|
515
|
+
**Công thức:**
|
|
490
516
|
|
|
491
|
-
Công thức mã hoá:
|
|
492
517
|
```
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
518
|
+
encrypted = Base64( IV[16 bytes] || AES_CBC_PKCS7( key, IV, plaintext ) )
|
|
519
|
+
|
|
520
|
+
key = SHA256( secretKey + timestamp )
|
|
521
|
+
IV = random 16 bytes (prepend vào ciphertext)
|
|
522
|
+
plaintext = JSON.stringify({ chỉ các trường PII })
|
|
496
523
|
```
|
|
497
524
|
|
|
498
|
-
|
|
525
|
+
> **Lưu ý:** Không bật trên dev/staging nếu server chưa cấu hình giải mã. Dùng `enableEncryption: false`.
|
|
499
526
|
|
|
500
527
|
---
|
|
501
528
|
|
|
502
|
-
|
|
529
|
+
### Best Practices
|
|
503
530
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
531
|
+
- Không log `secretKey` hay `apiKey` vào console production.
|
|
532
|
+
- Bật `debug: false` trên production build.
|
|
533
|
+
- Rotate key theo chính sách CDP team.
|
|
534
|
+
- Dùng environment variables, không hardcode credentials.
|
|
535
|
+
|
|
536
|
+
```typescript
|
|
537
|
+
// ✅ Đúng — dùng env vars
|
|
538
|
+
import Config from 'react-native-config';
|
|
539
|
+
|
|
540
|
+
const cdp = await CdpRnSdk.create({
|
|
541
|
+
apiKey: Config.CDP_API_KEY,
|
|
542
|
+
secretKey: Config.CDP_SECRET_KEY,
|
|
543
|
+
source: 'DOP',
|
|
544
|
+
serviceName: 'VC_APP',
|
|
545
|
+
debug: __DEV__,
|
|
546
|
+
});
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
```bash
|
|
550
|
+
# .env
|
|
551
|
+
CDP_API_KEY=YOUR_API_KEY
|
|
552
|
+
CDP_SECRET_KEY=YOUR_SECRET_KEY
|
|
553
|
+
CDP_BASE_URL=https://stg-ingestlog.vietcredit.com.vn
|
|
554
|
+
|
|
555
|
+
# .env.production
|
|
556
|
+
CDP_API_KEY=<production_key>
|
|
557
|
+
CDP_SECRET_KEY=<production_secret>
|
|
558
|
+
CDP_BASE_URL=https://ingestlog.vietcredit.com.vn
|
|
559
|
+
```
|
|
509
560
|
|
|
510
561
|
---
|
|
511
562
|
|
|
512
|
-
##
|
|
563
|
+
## Tích hợp React Navigation đầy đủ
|
|
513
564
|
|
|
514
|
-
|
|
565
|
+
Setup hoàn chỉnh với auto screen tracking và AppState flush:
|
|
515
566
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
567
|
+
```typescript
|
|
568
|
+
// src/lib/cdp.ts
|
|
569
|
+
import { CdpRnSdk } from 'vc-cdp-rn-sdk';
|
|
570
|
+
|
|
571
|
+
let _cdp: CdpRnSdk | null = null;
|
|
572
|
+
|
|
573
|
+
export async function initCdp(): Promise<CdpRnSdk> {
|
|
574
|
+
_cdp = await CdpRnSdk.create({
|
|
575
|
+
apiKey: process.env.CDP_API_KEY!,
|
|
576
|
+
secretKey: process.env.CDP_SECRET_KEY!,
|
|
577
|
+
source: 'DOP',
|
|
578
|
+
serviceName: 'VC_APP',
|
|
579
|
+
baseUrl: process.env.CDP_BASE_URL,
|
|
580
|
+
debug: __DEV__,
|
|
581
|
+
});
|
|
582
|
+
return _cdp;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
export function getCdp(): CdpRnSdk {
|
|
586
|
+
if (!_cdp) throw new Error('CDP SDK chưa được khởi tạo. Gọi initCdp() trước.');
|
|
587
|
+
return _cdp;
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
// App.tsx
|
|
593
|
+
import React, { useEffect, useRef } from 'react';
|
|
594
|
+
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
|
|
595
|
+
import { AppState, AppStateStatus } from 'react-native';
|
|
596
|
+
import { initCdp, getCdp } from './lib/cdp';
|
|
597
|
+
|
|
598
|
+
export default function App() {
|
|
599
|
+
const navRef = useNavigationContainerRef();
|
|
600
|
+
const appState = useRef(AppState.currentState);
|
|
601
|
+
|
|
602
|
+
useEffect(() => {
|
|
603
|
+
initCdp();
|
|
604
|
+
}, []);
|
|
605
|
+
|
|
606
|
+
// Flush khi app vào background
|
|
607
|
+
useEffect(() => {
|
|
608
|
+
const sub = AppState.addEventListener('change', async (next: AppStateStatus) => {
|
|
609
|
+
if (appState.current === 'active' && next.match(/inactive|background/)) {
|
|
610
|
+
await getCdp().flush();
|
|
611
|
+
}
|
|
612
|
+
appState.current = next;
|
|
613
|
+
});
|
|
614
|
+
return () => sub.remove();
|
|
615
|
+
}, []);
|
|
616
|
+
|
|
617
|
+
return (
|
|
618
|
+
<NavigationContainer
|
|
619
|
+
ref={navRef}
|
|
620
|
+
onReady={() => {
|
|
621
|
+
const name = navRef.getCurrentRoute()?.name;
|
|
622
|
+
if (name) getCdp().screen(name);
|
|
623
|
+
}}
|
|
624
|
+
onStateChange={() => {
|
|
625
|
+
const name = navRef.getCurrentRoute()?.name;
|
|
626
|
+
if (name) getCdp().screen(name);
|
|
627
|
+
}}
|
|
628
|
+
>
|
|
629
|
+
<RootNavigator />
|
|
630
|
+
</NavigationContainer>
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
```typescript
|
|
636
|
+
// Hook tiện lợi
|
|
637
|
+
// hooks/useCdp.ts
|
|
638
|
+
import { getCdp } from '../lib/cdp';
|
|
639
|
+
import type { CdpRnSdk } from 'vc-cdp-rn-sdk';
|
|
640
|
+
|
|
641
|
+
export function useCdp(): CdpRnSdk {
|
|
642
|
+
return getCdp();
|
|
643
|
+
}
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
```typescript
|
|
647
|
+
// Identify sau đăng nhập
|
|
648
|
+
async function handleLogin(phone: string, password: string) {
|
|
649
|
+
const user = await authApi.login(phone, password);
|
|
650
|
+
await getCdp().identifyUser(user.id, {
|
|
651
|
+
phone: user.phone,
|
|
652
|
+
email: user.email,
|
|
653
|
+
full_name: user.name,
|
|
654
|
+
});
|
|
655
|
+
navigation.navigate('Home');
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// Đăng xuất
|
|
659
|
+
async function handleLogout() {
|
|
660
|
+
await authApi.logout();
|
|
661
|
+
await getCdp().destroy_session();
|
|
662
|
+
navigation.reset({ index: 0, routes: [{ name: 'Login' }] });
|
|
663
|
+
}
|
|
664
|
+
```
|
|
540
665
|
|
|
541
666
|
---
|
|
542
667
|
|
|
543
|
-
##
|
|
668
|
+
## API Reference
|
|
544
669
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
670
|
+
### Factory
|
|
671
|
+
|
|
672
|
+
```typescript
|
|
673
|
+
static async create(config: CdpRnConfig): Promise<CdpRnSdk>
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### CdpRnConfig
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
interface CdpRnConfig {
|
|
680
|
+
apiKey: string; // bắt buộc
|
|
681
|
+
secretKey: string; // bắt buộc
|
|
682
|
+
source: string; // bắt buộc — kênh tích hợp
|
|
683
|
+
serviceName: string; // bắt buộc — VC_APP | DOP | LOS | LMS
|
|
684
|
+
baseUrl?: string; // mặc định staging
|
|
685
|
+
isTest?: boolean; // mặc định false
|
|
686
|
+
debug?: boolean; // mặc định false
|
|
687
|
+
batchSize?: number; // mặc định 10
|
|
688
|
+
batchInterval?: number; // mặc định 5000 ms
|
|
689
|
+
enableEncryption?: boolean; // mặc định true
|
|
690
|
+
}
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
### Profile Methods
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
async identifyUser(userId: string, traits?: UserTraits, partyType?: 'PERSON' | 'ORG'): Promise<this>
|
|
697
|
+
async identify(userId: string, traits?: UserTraits): Promise<this> // alias
|
|
698
|
+
|
|
699
|
+
async updateProfile(payload: {
|
|
700
|
+
profile_id?: string;
|
|
701
|
+
traits?: UserTraits;
|
|
702
|
+
consents?: ConsentInfo[];
|
|
703
|
+
scores?: ScoreInfo[];
|
|
704
|
+
products?: ProductInfo[];
|
|
705
|
+
metadata?: Record<string, unknown>;
|
|
706
|
+
}): Promise<ProfileResponse | undefined>
|
|
707
|
+
|
|
708
|
+
async getProfile(profileId?: string): Promise<ProfileData | undefined>
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### Trait Setter Methods (chainable → `this`)
|
|
712
|
+
|
|
713
|
+
```typescript
|
|
714
|
+
add_first_name(v: string): this
|
|
715
|
+
add_last_name(v: string): this
|
|
716
|
+
add_user_name(v: string): this
|
|
717
|
+
add_email(v: string): this
|
|
718
|
+
add_mobile(v: string): this
|
|
719
|
+
add_gender(v: 'M' | 'F' | 'O'): this
|
|
720
|
+
add_birthday(v: string | Date): this
|
|
721
|
+
add_idcard(v: string): this
|
|
722
|
+
add_old_idcard(v: string): this
|
|
723
|
+
add_address(v: string): this
|
|
724
|
+
add_occupation(v: string): this
|
|
725
|
+
add_nationality(v: string): this
|
|
726
|
+
add_marital_status(v: string): this
|
|
727
|
+
add_religion(v: string): this
|
|
728
|
+
add_zalo_id(v: string): this
|
|
729
|
+
add_tiktok_id(v: string): this
|
|
730
|
+
add_user_attribute(name: string, value: unknown): this
|
|
731
|
+
add_user_attributes(attrs: UserTraits): this
|
|
732
|
+
setUserAttributes(attrs: UserTraits): this
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
### Consent / Score / Product / Campaign Methods
|
|
736
|
+
|
|
737
|
+
```typescript
|
|
738
|
+
setConsents(consents: ConsentInfo[]): this
|
|
739
|
+
setScores(scores: ScoreInfo[]): this
|
|
740
|
+
setProducts(products: ProductInfo[]): this
|
|
741
|
+
setMetadata(meta: Record<string, unknown>): this
|
|
742
|
+
setCampaign(info: CampaignInfo): this
|
|
743
|
+
setPlatform(info: PlatformInfo): this
|
|
744
|
+
setPushToken(token: string): this
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
### Event Methods
|
|
748
|
+
|
|
749
|
+
```typescript
|
|
750
|
+
track(eventName: string, properties?: Record<string, unknown>): void
|
|
751
|
+
screen(screenName: string, properties?: Record<string, unknown>): void
|
|
752
|
+
async flush(): Promise<void>
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### Session & Identity Methods
|
|
756
|
+
|
|
757
|
+
```typescript
|
|
758
|
+
getUserIdentities(): UserIdentities
|
|
759
|
+
getProfileId(): string | null
|
|
760
|
+
getDeviceId(): string
|
|
761
|
+
getSessionId(): string
|
|
762
|
+
getUserAttribute(name: keyof UserTraits): unknown
|
|
763
|
+
|
|
764
|
+
async destroy_session(): Promise<this>
|
|
765
|
+
async reset(): Promise<this> // alias
|
|
766
|
+
async destroy(): Promise<void> // cleanup timers + flush
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### Types
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
interface UserTraits {
|
|
773
|
+
full_name?: string;
|
|
774
|
+
first_name?: string;
|
|
775
|
+
last_name?: string;
|
|
776
|
+
phone?: string; // 🔒 PII
|
|
777
|
+
email?: string; // 🔒 PII
|
|
778
|
+
gender?: 'M' | 'F' | 'O';
|
|
779
|
+
dob?: string; // 'yyyy-MM-dd'
|
|
780
|
+
idcard?: string; // 🔒 PII
|
|
781
|
+
old_idcard?: string; // 🔒 PII
|
|
782
|
+
address?: string; // 🔒 PII
|
|
783
|
+
occupation?: string;
|
|
784
|
+
nationality?: string;
|
|
785
|
+
marital_status?: string;
|
|
786
|
+
religion?: string; // 🔒 PII
|
|
787
|
+
zalo_id?: string;
|
|
788
|
+
tiktok_id?: string;
|
|
789
|
+
mps_verified?: boolean;
|
|
790
|
+
kyc_status?: string;
|
|
791
|
+
[key: string]: unknown;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
interface ConsentInfo {
|
|
795
|
+
consent_type: string;
|
|
796
|
+
status: boolean;
|
|
797
|
+
consent_date?: string; // 'yyyy-MM-dd'
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
interface ScoreInfo {
|
|
801
|
+
score_type: string;
|
|
802
|
+
score_value: number;
|
|
803
|
+
score_date?: string;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
interface ProductInfo {
|
|
807
|
+
product_code: string;
|
|
808
|
+
product_name?: string;
|
|
809
|
+
status?: string;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
interface UserIdentities {
|
|
813
|
+
user_id: string | null;
|
|
814
|
+
profile_id: string | null;
|
|
815
|
+
anonymous_id: string;
|
|
816
|
+
device_id: string;
|
|
817
|
+
session_id: string;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
interface ProfileResponse {
|
|
821
|
+
code: number;
|
|
822
|
+
message: string;
|
|
823
|
+
transaction_id: string;
|
|
824
|
+
profile_id: string;
|
|
825
|
+
}
|
|
826
|
+
```
|
package/docs/getting-started.md
CHANGED
|
@@ -149,8 +149,8 @@ await cdp.destroy_session();
|
|
|
149
149
|
|
|
150
150
|
## Bước tiếp theo
|
|
151
151
|
|
|
152
|
-
- [Profile & Traits →](profile.md)
|
|
153
|
-
- [Event Tracking →](events.md)
|
|
154
|
-
- [Tích hợp React Navigation →](integration-react-navigation.md)
|
|
155
|
-
- [Bảo mật →](security.md)
|
|
156
|
-
- [API Reference →](api-reference.md)
|
|
152
|
+
- [Profile & Traits →](https://gitlab.ovp.vn/dlc/vc-cdk-sdk/-/blob/master/vc-cdp-rn-sdk/docs/profile.md)
|
|
153
|
+
- [Event Tracking →](https://gitlab.ovp.vn/dlc/vc-cdk-sdk/-/blob/master/vc-cdp-rn-sdk/docs/events.md)
|
|
154
|
+
- [Tích hợp React Navigation →](https://gitlab.ovp.vn/dlc/vc-cdk-sdk/-/blob/master/vc-cdp-rn-sdk/docs/integration-react-navigation.md)
|
|
155
|
+
- [Bảo mật →](https://gitlab.ovp.vn/dlc/vc-cdk-sdk/-/blob/master/vc-cdp-rn-sdk/docs/security.md)
|
|
156
|
+
- [API Reference →](https://gitlab.ovp.vn/dlc/vc-cdk-sdk/-/blob/master/vc-cdp-rn-sdk/docs/api-reference.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vc-cdp-rn-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CDP SDK for React Native - Customer Data Platform tracking for iOS and Android",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
],
|
|
27
27
|
"author": "VietCredit",
|
|
28
28
|
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "https://gitlab.ovp.vn/dlc/vc-cdk-sdk.git",
|
|
32
|
+
"directory": "vc-cdp-rn-sdk"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://gitlab.ovp.vn/dlc/vc-cdk-sdk/-/tree/master/vc-cdp-rn-sdk#readme",
|
|
29
35
|
"peerDependencies": {
|
|
30
36
|
"@react-native-async-storage/async-storage": ">=1.17.0",
|
|
31
37
|
"react": ">=17.0.0",
|