guideai-app 0.4.1 → 0.4.2-1
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/API_DATA_CONTRACTS.md +516 -0
- package/API_SESSIONID_TESTING.md +215 -0
- package/PII_HASHING_EPIC.md +886 -0
- package/PII_HASHING_STORIES_SUMMARY.md +275 -0
- package/SESSION_ID_VERIFICATION.md +122 -0
- package/VISIT_COUNT_TESTING.md +453 -0
- package/dist/GuideAI.js +1 -1
- package/dist/GuideAI.js.LICENSE.txt +20 -0
- package/dist/GuideAI.js.map +1 -1
- package/dist/components/TranscriptBox.d.ts +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/metric/index.d.ts +0 -2
- package/dist/metric/metadata-tracker.d.ts +1 -2
- package/dist/styles/GuideAI.styles.d.ts +1 -1
- package/dist/types/GuideAI.types.d.ts +3 -1
- package/dist/types/metadata.types.d.ts +2 -0
- package/dist/utils/api.d.ts +5 -0
- package/dist/utils/elementInteractions.d.ts +92 -0
- package/dist/utils/gemini.d.ts +3 -0
- package/dist/utils/goToAElmLink.d.ts +1 -0
- package/dist/utils/highlightThenClick.d.ts +1 -0
- package/dist/utils/hoverThenClick.d.ts +1 -0
- package/dist/utils/logger.d.ts +1 -5
- package/dist/utils/session.d.ts +23 -0
- package/dist/utils/ui.d.ts +1 -1
- package/dist/visualContext/VisualContextScheduler.d.ts +43 -0
- package/dist/visualContext/VisualContextStore.d.ts +11 -0
- package/dist/visualContext/debug-overlay.d.ts +10 -0
- package/dist/visualContext/defaultProvider.d.ts +15 -0
- package/dist/visualContext/index.d.ts +5 -0
- package/dist/visualContext/types.d.ts +45 -0
- package/index.d.ts +5 -1
- package/jest.config.js +26 -0
- package/jest.setup.js +21 -0
- package/metadata-tracking-example.md +11 -11
- package/package.json +14 -3
- package/dist/metric/event-listner.d.ts +0 -141
- package/dist/utils/highlightAndClick.d.ts +0 -3
- package/dist/utils/hoverAndClick.d.ts +0 -4
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
# API Data Contracts
|
|
2
|
+
|
|
3
|
+
## `/initialize-session` Endpoint
|
|
4
|
+
|
|
5
|
+
### BEFORE Updates (Current/Legacy)
|
|
6
|
+
|
|
7
|
+
#### Request
|
|
8
|
+
```typescript
|
|
9
|
+
POST /initialize-session
|
|
10
|
+
|
|
11
|
+
Headers:
|
|
12
|
+
Content-Type: application/json
|
|
13
|
+
|
|
14
|
+
Body:
|
|
15
|
+
{
|
|
16
|
+
organizationKey: string; // Required
|
|
17
|
+
userId: "anonymous"; // Always "anonymous" (hardcoded)
|
|
18
|
+
date: string; // ISO date (YYYY-MM-DD)
|
|
19
|
+
time: string; // Time (HH:MM:SS)
|
|
20
|
+
messages: any[]; // Array (usually empty)
|
|
21
|
+
workflowKey?: string; // Optional
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Example:**
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"organizationKey": "demo-org-demo",
|
|
29
|
+
"userId": "anonymous",
|
|
30
|
+
"date": "2025-10-14",
|
|
31
|
+
"time": "14:30:00",
|
|
32
|
+
"messages": []
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### Response
|
|
37
|
+
```typescript
|
|
38
|
+
{
|
|
39
|
+
id: string; // Conversation ID
|
|
40
|
+
ephemeralToken: string; // Temporary auth token
|
|
41
|
+
prompt: string; // AI prompt/instructions
|
|
42
|
+
workflows: Workflow[]; // Array of workflow objects
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface Workflow {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
triggers: string[];
|
|
49
|
+
organizationKey: string;
|
|
50
|
+
prompt: string;
|
|
51
|
+
archived: boolean;
|
|
52
|
+
createdAt: string;
|
|
53
|
+
updatedAt: string;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Example:**
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"id": "conv-123-456",
|
|
61
|
+
"ephemeralToken": "eyJhbGc...",
|
|
62
|
+
"prompt": "You are a helpful AI assistant...",
|
|
63
|
+
"workflows": [
|
|
64
|
+
{
|
|
65
|
+
"id": "workflow-1",
|
|
66
|
+
"name": "Customer Support",
|
|
67
|
+
"triggers": ["help", "support"],
|
|
68
|
+
"organizationKey": "demo-org-demo",
|
|
69
|
+
"prompt": "Help the user with...",
|
|
70
|
+
"archived": false,
|
|
71
|
+
"createdAt": "2025-01-01T00:00:00Z",
|
|
72
|
+
"updatedAt": "2025-01-01T00:00:00Z"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### AFTER Updates (New Implementation)
|
|
81
|
+
|
|
82
|
+
#### Request
|
|
83
|
+
```typescript
|
|
84
|
+
POST /initialize-session
|
|
85
|
+
|
|
86
|
+
Headers:
|
|
87
|
+
Content-Type: application/json
|
|
88
|
+
|
|
89
|
+
Body:
|
|
90
|
+
{
|
|
91
|
+
organizationKey: string; // Required
|
|
92
|
+
userId: string; // NEW: Email if available, or "anonymous"
|
|
93
|
+
email?: string; // NEW: Explicit email field (undefined if not available)
|
|
94
|
+
date: string; // ISO date (YYYY-MM-DD)
|
|
95
|
+
time: string; // Time (HH:MM:SS)
|
|
96
|
+
messages: any[]; // Array (usually empty)
|
|
97
|
+
workflowKey?: string; // Optional
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Example 1: Authenticated User**
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"organizationKey": "demo-org-demo",
|
|
105
|
+
"userId": "csdemo@demo-org.com",
|
|
106
|
+
"email": "csdemo@demo-org.com",
|
|
107
|
+
"date": "2025-10-14",
|
|
108
|
+
"time": "14:30:00",
|
|
109
|
+
"messages": []
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Example 2: Anonymous User**
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"organizationKey": "demo-org-demo",
|
|
117
|
+
"userId": "anonymous",
|
|
118
|
+
"email": undefined, // Or omitted
|
|
119
|
+
"date": "2025-10-14",
|
|
120
|
+
"time": "14:30:00",
|
|
121
|
+
"messages": []
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Response
|
|
126
|
+
```typescript
|
|
127
|
+
{
|
|
128
|
+
id: string; // Conversation ID
|
|
129
|
+
ephemeralToken: string; // Temporary auth token
|
|
130
|
+
prompt: string; // AI prompt/instructions
|
|
131
|
+
workflows: Workflow[]; // Array of workflow objects
|
|
132
|
+
userMetadata?: { // NEW: User metadata (optional)
|
|
133
|
+
visitCount: number; // Number of visits for this user
|
|
134
|
+
loginCount?: number; // Number of logins (optional)
|
|
135
|
+
email?: string; // User email (if available)
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Example 1: Authenticated User Response**
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"id": "conv-123-456",
|
|
144
|
+
"ephemeralToken": "eyJhbGc...",
|
|
145
|
+
"prompt": "You are a helpful AI assistant...",
|
|
146
|
+
"workflows": [...],
|
|
147
|
+
"userMetadata": {
|
|
148
|
+
"visitCount": 5,
|
|
149
|
+
"loginCount": 2,
|
|
150
|
+
"email": "csdemo@demo-org.com"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Example 2: Anonymous User Response**
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"id": "conv-123-456",
|
|
159
|
+
"ephemeralToken": "eyJhbGc...",
|
|
160
|
+
"prompt": "You are a helpful AI assistant...",
|
|
161
|
+
"workflows": [...],
|
|
162
|
+
"userMetadata": {
|
|
163
|
+
"visitCount": 0
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## `/metadata-updates` Endpoint
|
|
171
|
+
|
|
172
|
+
### Request (Already Implemented)
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
POST /metadata-updates
|
|
176
|
+
|
|
177
|
+
Headers:
|
|
178
|
+
Content-Type: application/json
|
|
179
|
+
|
|
180
|
+
Body:
|
|
181
|
+
{
|
|
182
|
+
organizationKey: string; // Required
|
|
183
|
+
updates: MetadataUpdate[]; // Array of metadata updates
|
|
184
|
+
batchTimestamp: number; // Timestamp when batch was created
|
|
185
|
+
updateCount: number; // Number of updates in batch
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
interface MetadataUpdate {
|
|
189
|
+
type: 'visit' | 'login' | 'user_info' | 'session' | 'custom';
|
|
190
|
+
timestamp: number; // Unix timestamp (milliseconds)
|
|
191
|
+
data: {
|
|
192
|
+
sessionId: string; // Current session ID
|
|
193
|
+
email?: string; // User email (if available) ← KEY FOR STORAGE
|
|
194
|
+
visitCount?: number; // Current visit count
|
|
195
|
+
loginCount?: number; // Current login count
|
|
196
|
+
firstVisit?: number; // First visit timestamp
|
|
197
|
+
lastVisit?: number; // Last visit timestamp
|
|
198
|
+
[key: string]: any; // Other custom fields
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Example Request
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"organizationKey": "demo-org-demo",
|
|
208
|
+
"updates": [
|
|
209
|
+
{
|
|
210
|
+
"type": "visit",
|
|
211
|
+
"timestamp": 1697295600000,
|
|
212
|
+
"data": {
|
|
213
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
214
|
+
"email": "csdemo@demo-org.com",
|
|
215
|
+
"firstVisit": 1697000000000,
|
|
216
|
+
"lastVisit": 1697295600000,
|
|
217
|
+
"visitCount": 5
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"type": "login",
|
|
222
|
+
"timestamp": 1697295650000,
|
|
223
|
+
"data": {
|
|
224
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
225
|
+
"email": "csdemo@demo-org.com",
|
|
226
|
+
"loginCount": 2,
|
|
227
|
+
"lastLogin": 1697295650000
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
],
|
|
231
|
+
"batchTimestamp": 1697295600000,
|
|
232
|
+
"updateCount": 2
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Response
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
{
|
|
240
|
+
success: boolean; // Whether the update was successful
|
|
241
|
+
message?: string; // Optional message
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Example:**
|
|
246
|
+
```json
|
|
247
|
+
{
|
|
248
|
+
"success": true
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Backend Implementation Notes
|
|
255
|
+
|
|
256
|
+
### Key Changes Required
|
|
257
|
+
|
|
258
|
+
1. **Accept email in `/initialize-session`**
|
|
259
|
+
- Read `email` from request body
|
|
260
|
+
- Use as user identifier (along with organizationKey)
|
|
261
|
+
|
|
262
|
+
2. **Return userMetadata in `/initialize-session` response**
|
|
263
|
+
- Look up user by `organizationKey + email`
|
|
264
|
+
- Return their visitCount from database
|
|
265
|
+
- If not found or anonymous, return `visitCount: 0`
|
|
266
|
+
|
|
267
|
+
3. **Store visitCount from `/metadata-updates`**
|
|
268
|
+
- Extract `email` from each update's data
|
|
269
|
+
- Store visitCount in database by `organizationKey + email`
|
|
270
|
+
- Update on each request (upsert operation)
|
|
271
|
+
|
|
272
|
+
### Database Schema Suggestion
|
|
273
|
+
|
|
274
|
+
```sql
|
|
275
|
+
-- User metadata table
|
|
276
|
+
CREATE TABLE user_metadata (
|
|
277
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
278
|
+
organization_key VARCHAR(255) NOT NULL,
|
|
279
|
+
email VARCHAR(255) NOT NULL,
|
|
280
|
+
visit_count INTEGER DEFAULT 0,
|
|
281
|
+
login_count INTEGER DEFAULT 0,
|
|
282
|
+
first_visit BIGINT, -- Unix timestamp (ms)
|
|
283
|
+
last_visit BIGINT, -- Unix timestamp (ms)
|
|
284
|
+
last_login BIGINT, -- Unix timestamp (ms)
|
|
285
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
286
|
+
updated_at TIMESTAMP DEFAULT NOW(),
|
|
287
|
+
UNIQUE(organization_key, email)
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
-- Index for fast lookups
|
|
291
|
+
CREATE INDEX idx_user_metadata_lookup ON user_metadata(organization_key, email);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Backend Logic Pseudocode
|
|
295
|
+
|
|
296
|
+
#### For `/initialize-session`:
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
def initialize_session(request):
|
|
300
|
+
org_key = request.organizationKey
|
|
301
|
+
email = request.email
|
|
302
|
+
|
|
303
|
+
# Look up user metadata
|
|
304
|
+
if email and email != 'anonymous':
|
|
305
|
+
user = db.query(
|
|
306
|
+
"SELECT * FROM user_metadata WHERE organization_key = ? AND email = ?",
|
|
307
|
+
org_key, email
|
|
308
|
+
)
|
|
309
|
+
visit_count = user.visit_count if user else 0
|
|
310
|
+
login_count = user.login_count if user else 0
|
|
311
|
+
else:
|
|
312
|
+
# Anonymous user
|
|
313
|
+
visit_count = 0
|
|
314
|
+
login_count = 0
|
|
315
|
+
|
|
316
|
+
# Return response with userMetadata
|
|
317
|
+
return {
|
|
318
|
+
"id": generate_conversation_id(),
|
|
319
|
+
"ephemeralToken": generate_token(),
|
|
320
|
+
"prompt": get_prompt(),
|
|
321
|
+
"workflows": get_workflows(org_key),
|
|
322
|
+
"userMetadata": {
|
|
323
|
+
"visitCount": visit_count,
|
|
324
|
+
"loginCount": login_count,
|
|
325
|
+
"email": email if email != 'anonymous' else None
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
#### For `/metadata-updates`:
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
def metadata_updates(request):
|
|
334
|
+
org_key = request.organizationKey
|
|
335
|
+
updates = request.updates
|
|
336
|
+
|
|
337
|
+
for update in updates:
|
|
338
|
+
email = update.data.get('email')
|
|
339
|
+
|
|
340
|
+
if email and email != 'anonymous':
|
|
341
|
+
# Update or create user metadata
|
|
342
|
+
if update.type == 'visit':
|
|
343
|
+
db.upsert(
|
|
344
|
+
"user_metadata",
|
|
345
|
+
organization_key=org_key,
|
|
346
|
+
email=email,
|
|
347
|
+
visit_count=update.data.get('visitCount'),
|
|
348
|
+
first_visit=update.data.get('firstVisit'),
|
|
349
|
+
last_visit=update.data.get('lastVisit')
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
elif update.type == 'login':
|
|
353
|
+
db.upsert(
|
|
354
|
+
"user_metadata",
|
|
355
|
+
organization_key=org_key,
|
|
356
|
+
email=email,
|
|
357
|
+
login_count=update.data.get('loginCount'),
|
|
358
|
+
last_login=update.data.get('lastLogin')
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
return {"success": True}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## Testing the Changes
|
|
367
|
+
|
|
368
|
+
### Test 1: Authenticated User Flow
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# Step 1: Initialize session with email
|
|
372
|
+
curl -X POST https://your-api.com/initialize-session \
|
|
373
|
+
-H "Content-Type: application/json" \
|
|
374
|
+
-d '{
|
|
375
|
+
"organizationKey": "test-org",
|
|
376
|
+
"userId": "test@example.com",
|
|
377
|
+
"email": "test@example.com",
|
|
378
|
+
"date": "2025-10-14",
|
|
379
|
+
"time": "12:00:00",
|
|
380
|
+
"messages": []
|
|
381
|
+
}'
|
|
382
|
+
|
|
383
|
+
# Expected response:
|
|
384
|
+
# {
|
|
385
|
+
# "id": "conv-123",
|
|
386
|
+
# "ephemeralToken": "...",
|
|
387
|
+
# "prompt": "...",
|
|
388
|
+
# "workflows": [],
|
|
389
|
+
# "userMetadata": {
|
|
390
|
+
# "visitCount": 0, // First time
|
|
391
|
+
# "email": "test@example.com"
|
|
392
|
+
# }
|
|
393
|
+
# }
|
|
394
|
+
|
|
395
|
+
# Step 2: Send metadata update (simulate visit)
|
|
396
|
+
curl -X POST https://your-api.com/metadata-updates \
|
|
397
|
+
-H "Content-Type: application/json" \
|
|
398
|
+
-d '{
|
|
399
|
+
"organizationKey": "test-org",
|
|
400
|
+
"updates": [
|
|
401
|
+
{
|
|
402
|
+
"type": "visit",
|
|
403
|
+
"timestamp": 1697295600000,
|
|
404
|
+
"data": {
|
|
405
|
+
"sessionId": "session-123",
|
|
406
|
+
"email": "test@example.com",
|
|
407
|
+
"visitCount": 1,
|
|
408
|
+
"firstVisit": 1697295600000,
|
|
409
|
+
"lastVisit": 1697295600000
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
],
|
|
413
|
+
"batchTimestamp": 1697295600000,
|
|
414
|
+
"updateCount": 1
|
|
415
|
+
}'
|
|
416
|
+
|
|
417
|
+
# Expected response:
|
|
418
|
+
# { "success": true }
|
|
419
|
+
|
|
420
|
+
# Step 3: Initialize session again (should return visitCount = 1)
|
|
421
|
+
curl -X POST https://your-api.com/initialize-session \
|
|
422
|
+
-H "Content-Type: application/json" \
|
|
423
|
+
-d '{
|
|
424
|
+
"organizationKey": "test-org",
|
|
425
|
+
"userId": "test@example.com",
|
|
426
|
+
"email": "test@example.com",
|
|
427
|
+
"date": "2025-10-14",
|
|
428
|
+
"time": "13:00:00",
|
|
429
|
+
"messages": []
|
|
430
|
+
}'
|
|
431
|
+
|
|
432
|
+
# Expected response:
|
|
433
|
+
# {
|
|
434
|
+
# "userMetadata": {
|
|
435
|
+
# "visitCount": 1 // ← Should return stored value
|
|
436
|
+
# }
|
|
437
|
+
# }
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Test 2: Anonymous User Flow
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
# Initialize session without email
|
|
444
|
+
curl -X POST https://your-api.com/initialize-session \
|
|
445
|
+
-H "Content-Type: application/json" \
|
|
446
|
+
-d '{
|
|
447
|
+
"organizationKey": "test-org",
|
|
448
|
+
"userId": "anonymous",
|
|
449
|
+
"date": "2025-10-14",
|
|
450
|
+
"time": "12:00:00",
|
|
451
|
+
"messages": []
|
|
452
|
+
}'
|
|
453
|
+
|
|
454
|
+
# Expected response:
|
|
455
|
+
# {
|
|
456
|
+
# "userMetadata": {
|
|
457
|
+
# "visitCount": 0 // Always 0 for anonymous
|
|
458
|
+
# }
|
|
459
|
+
# }
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## Backward Compatibility
|
|
465
|
+
|
|
466
|
+
### Will Old Clients Break?
|
|
467
|
+
|
|
468
|
+
**NO** - The implementation is backward compatible:
|
|
469
|
+
|
|
470
|
+
1. **Old FE + New BE**: Works fine
|
|
471
|
+
- Old FE sends `userId: "anonymous"`
|
|
472
|
+
- New BE returns `userMetadata` (optional field)
|
|
473
|
+
- Old FE ignores the new field
|
|
474
|
+
|
|
475
|
+
2. **New FE + Old BE**: Works fine
|
|
476
|
+
- New FE sends `email` field
|
|
477
|
+
- Old BE ignores unknown fields
|
|
478
|
+
- New FE handles missing `userMetadata` gracefully
|
|
479
|
+
|
|
480
|
+
3. **New FE + New BE**: Full functionality
|
|
481
|
+
- Email-based user identification
|
|
482
|
+
- Cross-browser visitCount tracking
|
|
483
|
+
- Everything works as designed
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## Summary
|
|
488
|
+
|
|
489
|
+
### Changed Fields in `/initialize-session`
|
|
490
|
+
|
|
491
|
+
| Field | Before | After | Required |
|
|
492
|
+
|-------|--------|-------|----------|
|
|
493
|
+
| `userId` | Always "anonymous" | Email or "anonymous" | Yes |
|
|
494
|
+
| `email` | N/A | Email string | No (undefined if not available) |
|
|
495
|
+
| `userMetadata` (response) | N/A | Object with visitCount | No (optional) |
|
|
496
|
+
|
|
497
|
+
### Key for Backend Team
|
|
498
|
+
|
|
499
|
+
✅ **Must implement:**
|
|
500
|
+
1. Read `email` from request
|
|
501
|
+
2. Return `userMetadata.visitCount` in response
|
|
502
|
+
3. Store visitCount from `/metadata-updates` by `organizationKey + email`
|
|
503
|
+
|
|
504
|
+
✅ **Nice to have:**
|
|
505
|
+
4. Store by sessionId for anonymous users (temporary tracking)
|
|
506
|
+
5. Return loginCount in userMetadata
|
|
507
|
+
6. Add database indexes for performance
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
## Questions?
|
|
512
|
+
|
|
513
|
+
Contact the development team or refer to:
|
|
514
|
+
- `src/utils/USER_IDENTIFICATION_NOTES.md` - Full documentation
|
|
515
|
+
- `IMPLEMENTATION_SUMMARY.md` - Implementation details
|
|
516
|
+
|