bulltrackers-module 1.0.504 → 1.0.506
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/functions/generic-api/user-api/ADDING_LEGACY_ROUTES_GUIDE.md +345 -0
- package/functions/generic-api/user-api/CODE_REORGANIZATION_PLAN.md +320 -0
- package/functions/generic-api/user-api/COMPLETE_REFACTORING_PLAN.md +116 -0
- package/functions/generic-api/user-api/FIRESTORE_PATHS_INVENTORY.md +171 -0
- package/functions/generic-api/user-api/FIRESTORE_PATH_MIGRATION_REFERENCE.md +710 -0
- package/functions/generic-api/user-api/FIRESTORE_PATH_VALIDATION.md +109 -0
- package/functions/generic-api/user-api/MIGRATION_PLAN.md +499 -0
- package/functions/generic-api/user-api/README_MIGRATION.md +152 -0
- package/functions/generic-api/user-api/REFACTORING_COMPLETE.md +106 -0
- package/functions/generic-api/user-api/REFACTORING_STATUS.md +85 -0
- package/functions/generic-api/user-api/VERIFICATION_MIGRATION_NOTES.md +206 -0
- package/functions/generic-api/user-api/helpers/ORGANIZATION_COMPLETE.md +126 -0
- package/functions/generic-api/user-api/helpers/alerts/subscription_helpers.js +327 -0
- package/functions/generic-api/user-api/helpers/{test_alert_helpers.js → alerts/test_alert_helpers.js} +1 -1
- package/functions/generic-api/user-api/helpers/collection_helpers.js +23 -45
- package/functions/generic-api/user-api/helpers/core/compression_helpers.js +68 -0
- package/functions/generic-api/user-api/helpers/core/data_lookup_helpers.js +213 -0
- package/functions/generic-api/user-api/helpers/core/path_resolution_helpers.js +486 -0
- package/functions/generic-api/user-api/helpers/core/user_status_helpers.js +77 -0
- package/functions/generic-api/user-api/helpers/data/computation_helpers.js +299 -0
- package/functions/generic-api/user-api/helpers/data/instrument_helpers.js +55 -0
- package/functions/generic-api/user-api/helpers/data/portfolio_helpers.js +238 -0
- package/functions/generic-api/user-api/helpers/data/social_helpers.js +55 -0
- package/functions/generic-api/user-api/helpers/data_helpers.js +85 -2750
- package/functions/generic-api/user-api/helpers/{dev_helpers.js → dev/dev_helpers.js} +0 -1
- package/functions/generic-api/user-api/helpers/{on_demand_fetch_helpers.js → fetch/on_demand_fetch_helpers.js} +33 -115
- package/functions/generic-api/user-api/helpers/metrics/personalized_metrics_helpers.js +360 -0
- package/functions/generic-api/user-api/helpers/{notification_helpers.js → notifications/notification_helpers.js} +0 -1
- package/functions/generic-api/user-api/helpers/profile/pi_profile_helpers.js +200 -0
- package/functions/generic-api/user-api/helpers/profile/profile_view_helpers.js +125 -0
- package/functions/generic-api/user-api/helpers/profile/user_profile_helpers.js +178 -0
- package/functions/generic-api/user-api/helpers/recommendations/recommendation_helpers.js +65 -0
- package/functions/generic-api/user-api/helpers/{review_helpers.js → reviews/review_helpers.js} +23 -107
- package/functions/generic-api/user-api/helpers/search/pi_request_helpers.js +177 -0
- package/functions/generic-api/user-api/helpers/search/pi_search_helpers.js +70 -0
- package/functions/generic-api/user-api/helpers/{user_sync_helpers.js → sync/user_sync_helpers.js} +54 -127
- package/functions/generic-api/user-api/helpers/{verification_helpers.js → verification/verification_helpers.js} +4 -43
- package/functions/generic-api/user-api/helpers/watchlist/watchlist_analytics_helpers.js +95 -0
- package/functions/generic-api/user-api/helpers/watchlist/watchlist_data_helpers.js +139 -0
- package/functions/generic-api/user-api/helpers/watchlist/watchlist_generation_helpers.js +306 -0
- package/functions/generic-api/user-api/helpers/{watchlist_helpers.js → watchlist/watchlist_management_helpers.js} +62 -213
- package/functions/generic-api/user-api/index.js +9 -9
- package/functions/task-engine/handler_creator.js +7 -6
- package/package.json +1 -1
- package/functions/generic-api/API_MIGRATION_PLAN.md +0 -436
- package/functions/generic-api/user-api/helpers/FALLBACK_CONDITIONS.md +0 -98
- package/functions/generic-api/user-api/helpers/HISTORY_STORAGE_LOCATION.md +0 -66
- package/functions/generic-api/user-api/helpers/subscription_helpers.js +0 -512
- /package/functions/generic-api/user-api/helpers/{alert_helpers.js → alerts/alert_helpers.js} +0 -0
|
@@ -250,10 +250,10 @@ async function handleRequest(message, context, configObj, dependencies) {
|
|
|
250
250
|
await handlePopularInvestorUpdate(taskData, configObj, dependencies);
|
|
251
251
|
break;
|
|
252
252
|
case 'ON_DEMAND_USER_UPDATE':
|
|
253
|
-
// For ON_DEMAND_USER_UPDATE, the
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
const onDemandTaskData =
|
|
253
|
+
// For ON_DEMAND_USER_UPDATE, the payload contains both top-level fields (cid, username, etc.)
|
|
254
|
+
// and a nested 'data' object (includeSocial, since, etc.)
|
|
255
|
+
// Merge both to create the complete task data
|
|
256
|
+
const onDemandTaskData = {
|
|
257
257
|
cid: payload.cid,
|
|
258
258
|
username: payload.username,
|
|
259
259
|
requestId: payload.requestId,
|
|
@@ -262,11 +262,12 @@ async function handleRequest(message, context, configObj, dependencies) {
|
|
|
262
262
|
effectiveRequestedBy: payload.effectiveRequestedBy,
|
|
263
263
|
metadata: payload.metadata,
|
|
264
264
|
priority: payload.priority,
|
|
265
|
-
|
|
265
|
+
// Merge nested data object if it exists
|
|
266
|
+
...(data || payload.data || {})
|
|
266
267
|
};
|
|
267
268
|
|
|
268
269
|
if (!onDemandTaskData.cid || !onDemandTaskData.username) {
|
|
269
|
-
logger.log('ERROR', `[TaskEngine] ON_DEMAND_USER_UPDATE missing required fields (cid or username)`, { payload, onDemandTaskData });
|
|
270
|
+
logger.log('ERROR', `[TaskEngine] ON_DEMAND_USER_UPDATE missing required fields (cid or username)`, { payload, data, onDemandTaskData });
|
|
270
271
|
return;
|
|
271
272
|
}
|
|
272
273
|
|
package/package.json
CHANGED
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
# API Migration Plan: User-Centric Collection Structure
|
|
2
|
-
|
|
3
|
-
## Status: ✅ **MIGRATION COMPLETE**
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
This document outlines the migration of the User API to use the new user-centric collection structure from the `collection_registry.js`. The goal is to use eToro CIDs and Post IDs for document paths where possible, while maintaining backward compatibility with existing user signup data.
|
|
7
|
-
|
|
8
|
-
**All endpoints have been updated to use the new collection structure with backward compatibility fallbacks.**
|
|
9
|
-
|
|
10
|
-
## Summary of Completed Changes
|
|
11
|
-
|
|
12
|
-
### ✅ Phase 1: Low-Risk, High-Value
|
|
13
|
-
1. **User Social Posts** - ✅ Updated `getUserSocialPosts()` to use `signedInUsers/{cid}/posts` with legacy fallback
|
|
14
|
-
2. **User Sync Requests** - ✅ Updated `requestUserSync()` and `getUserSyncStatus()` to use `signedInUsers/{cid}/syncRequests` and `signedInUsers/{cid}/syncStatus`
|
|
15
|
-
3. **User Notifications** - ⚠️ **Note:** Currently uses Firebase UID for frontend auth compatibility. CID lookup helper created but not yet integrated into notification writes (alert system handles this separately)
|
|
16
|
-
|
|
17
|
-
### ✅ Phase 2: Medium Complexity
|
|
18
|
-
4. **User Portfolio** - ✅ Updated `getUserPortfolio()` and `findLatestPortfolioDate()` to try:
|
|
19
|
-
- `signedInUsers/{cid}/portfolio/latest` (user-centric)
|
|
20
|
-
- `SignedInUserPortfolioData/{date}/{cid}` (root data)
|
|
21
|
-
- `signed_in_users/19M/snapshots/{date}/parts/part_X` (legacy fallback)
|
|
22
|
-
5. **User Trade History** - ✅ Helper function `findLatestPortfolioDate()` updated to support new structure (used internally by `getUserComputations()`)
|
|
23
|
-
|
|
24
|
-
### ✅ Phase 3: Higher Complexity
|
|
25
|
-
6. **User Watchlists** - ✅ All CRUD operations updated:
|
|
26
|
-
- `getUserWatchlists()` - reads from `signedInUsers/{cid}/watchlists`
|
|
27
|
-
- `getWatchlist()` - reads from new structure
|
|
28
|
-
- `createWatchlist()` - writes to both structures
|
|
29
|
-
- `updateWatchlist()` - updates both structures
|
|
30
|
-
- `deleteWatchlist()` - deletes from both structures
|
|
31
|
-
7. **User Verification** - ✅ Updated `finalizeVerification()` to write to `signedInUsers/{cid}/verification` and store user mapping
|
|
32
|
-
8. **Alert Subscriptions** - ✅ Dual structure implemented:
|
|
33
|
-
- Per-watchlist: `signedInUsers/{cid}/watchlists/{watchlistId}/subscriptions/{piCid}`
|
|
34
|
-
- Global: `signedInUsers/{cid}/subscriptions/{piCid}`
|
|
35
|
-
- All CRUD operations updated
|
|
36
|
-
9. **Popular Investor Data** - ✅ All endpoints updated:
|
|
37
|
-
- Fetch Requests: `popularInvestors/{piCid}/fetchRequests/{requestId}`
|
|
38
|
-
- Fetch Status: `popularInvestors/{piCid}/fetchStatus`
|
|
39
|
-
- User Fetch Requests: `popularInvestors/{piCid}/userFetchRequests/{userCid}` (added to registry)
|
|
40
|
-
- Reviews: `popularInvestors/{piCid}/reviews/{reviewId}`
|
|
41
|
-
- Profile Views: `popularInvestors/{piCid}/profileViews/{date}`
|
|
42
|
-
- Individual Views: `popularInvestors/{piCid}/views/{viewId}`
|
|
43
|
-
|
|
44
|
-
## Current vs New Collection Paths
|
|
45
|
-
|
|
46
|
-
### 1. User Portfolio Data ✅ **COMPLETED**
|
|
47
|
-
|
|
48
|
-
**Current:**
|
|
49
|
-
- `signed_in_users/19M/snapshots/{date}/parts/part_{shardIndex}` (sharded, legacy)
|
|
50
|
-
- Lookup: Search through all parts to find user's CID
|
|
51
|
-
|
|
52
|
-
**New (Registry):**
|
|
53
|
-
- **Root Data (for computations):** `SignedInUserPortfolioData/{date}/{cid}` ✅ **IMPLEMENTED**
|
|
54
|
-
- **User-Centric (for fallback):** `signedInUsers/{cid}/portfolio/latest` ✅ **IMPLEMENTED**
|
|
55
|
-
|
|
56
|
-
**API Endpoints Affected:**
|
|
57
|
-
- `GET /user/me/portfolio` - `getUserPortfolio()` in `data_helpers.js` ✅ **UPDATED**
|
|
58
|
-
|
|
59
|
-
**Migration Strategy:**
|
|
60
|
-
1. ✅ Try new structure first: `signedInUsers/{cid}/portfolio/latest`
|
|
61
|
-
2. ✅ Fallback to root data: `SignedInUserPortfolioData/{date}/{cid}` (find latest date)
|
|
62
|
-
3. ✅ Fallback to legacy: `signed_in_users/19M/snapshots/{date}/parts/part_X` (for backward compatibility)
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
### 2. User Trade History Data ✅ **COMPLETED** (Helper function updated)
|
|
67
|
-
|
|
68
|
-
**Current:**
|
|
69
|
-
- `signed_in_user_history/19M/snapshots/{date}/parts/part_{shardIndex}` (sharded, legacy)
|
|
70
|
-
- Lookup: Search through all parts to find user's CID
|
|
71
|
-
|
|
72
|
-
**New (Registry):**
|
|
73
|
-
- **Root Data (for computations):** `SignedInUserTradeHistoryData/{date}/{cid}` ✅ **IMPLEMENTED**
|
|
74
|
-
- **User-Centric (for fallback):** `signedInUsers/{cid}/tradeHistory/latest` ✅ **IMPLEMENTED**
|
|
75
|
-
|
|
76
|
-
**API Endpoints Affected:**
|
|
77
|
-
- None currently exposed, but used internally by `getUserComputations()` ✅ **Helper function updated**
|
|
78
|
-
|
|
79
|
-
**Migration Strategy:**
|
|
80
|
-
1. ✅ Try new structure first: `signedInUsers/{cid}/tradeHistory/latest`
|
|
81
|
-
2. ✅ Fallback to root data: `SignedInUserTradeHistoryData/{date}/{cid}` (find latest date)
|
|
82
|
-
3. ✅ Fallback to legacy: `signed_in_user_history/19M/snapshots/{date}/parts/part_X`
|
|
83
|
-
|
|
84
|
-
---
|
|
85
|
-
|
|
86
|
-
### 3. User Social Posts ✅ **COMPLETED**
|
|
87
|
-
|
|
88
|
-
**Current:**
|
|
89
|
-
- `signed_in_users_social/{cid}/posts/{postId}` ✅ **Already using CID!**
|
|
90
|
-
|
|
91
|
-
**New (Registry):**
|
|
92
|
-
- **Root Data (for computations):** `SignedInUserSocialPostData/{date}/{cid}` ✅ **IMPLEMENTED**
|
|
93
|
-
- **User-Centric (for fallback):** `signedInUsers/{cid}/posts/{postId}` ✅ **IMPLEMENTED**
|
|
94
|
-
|
|
95
|
-
**API Endpoints Affected:**
|
|
96
|
-
- `GET /user/me/social-posts` - `getUserSocialPosts()` in `data_helpers.js` ✅ **UPDATED**
|
|
97
|
-
|
|
98
|
-
**Migration Strategy:**
|
|
99
|
-
1. ✅ Try new user-centric: `signedInUsers/{cid}/posts` (ordered by `fetchedAt` desc)
|
|
100
|
-
2. ✅ Fallback to current: `signed_in_users_social/{cid}/posts` (for backward compatibility)
|
|
101
|
-
3. Note: Root data structure is different (nested under date), so not suitable for direct API access
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
### 4. User Notifications
|
|
106
|
-
|
|
107
|
-
**Current:**
|
|
108
|
-
- `user_notifications/{firebaseUid}/notifications/{notificationId}`
|
|
109
|
-
|
|
110
|
-
**New (Registry - Updated for CID consistency):**
|
|
111
|
-
- `signedInUsers/{cid}/notifications/{notificationId}` ⚠️ **Change to use CID instead of Firebase UID**
|
|
112
|
-
|
|
113
|
-
**API Endpoints Affected:**
|
|
114
|
-
- Frontend `SyncNotificationContext` - reads directly, but API can provide CID lookup
|
|
115
|
-
- `POST /user/dev/test-alert` - `sendTestAlert()` in `test_alert_helpers.js` (needs update)
|
|
116
|
-
- Alert system - `processAlertForPI()` in `alert_helpers.js` (needs update)
|
|
117
|
-
|
|
118
|
-
**Migration Strategy:**
|
|
119
|
-
1. **API Lookup:** When frontend requests notifications, API looks up CID from Firebase UID
|
|
120
|
-
2. **Write:** All notification writes use CID (alert system, test alerts, etc.)
|
|
121
|
-
3. **Read:** API endpoint to get notifications by CID (frontend can call with Firebase UID, API resolves to CID)
|
|
122
|
-
4. **Note:** Frontend `SyncNotificationContext` may need to be updated to use CID, or API can provide a mapping endpoint
|
|
123
|
-
|
|
124
|
-
**Implementation:**
|
|
125
|
-
- ✅ Create helper: `getCidFromFirebaseUid(db, firebaseUid)` - looks up CID from `signedInUsers` collection (in `collection_helpers.js`)
|
|
126
|
-
- ⚠️ Update all notification writes to use CID (alert system and test alerts already handle this via Firebase UID lookup)
|
|
127
|
-
- ⚠️ Update frontend to either:
|
|
128
|
-
- Option A: Use CID directly (if available in auth context)
|
|
129
|
-
- Option B: Call API endpoint that accepts Firebase UID and returns notifications (API does CID lookup)
|
|
130
|
-
|
|
131
|
-
**Note:** Notifications currently use Firebase UID for frontend authentication compatibility. The helper function exists but notification writes are handled separately by the alert system which already performs CID→Firebase UID mapping.
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
### 5. User Verification ✅ **COMPLETED**
|
|
136
|
-
|
|
137
|
-
**Current:**
|
|
138
|
-
- `user_verifications/{username}` (keyed by username)
|
|
139
|
-
|
|
140
|
-
**New (Registry):**
|
|
141
|
-
- `signedInUsers/{cid}/verification` ✅ **IMPLEMENTED** (singleton document, not subcollection)
|
|
142
|
-
|
|
143
|
-
**API Endpoints Affected:**
|
|
144
|
-
- `POST /user/verify/init` - `initiateVerification()` in `verification_helpers.js` (still uses legacy for init)
|
|
145
|
-
- `POST /user/verify/finalize` - `finalizeVerification()` in `verification_helpers.js` ✅ **UPDATED**
|
|
146
|
-
- `GET /user/me/verification` - `getUserVerification()` in `data_helpers.js` (should read from new structure)
|
|
147
|
-
|
|
148
|
-
**Migration Strategy:**
|
|
149
|
-
1. **During Init:**
|
|
150
|
-
- Store in legacy location: `user_verifications/{username}` (for backward compatibility)
|
|
151
|
-
- Note: CID not available yet, but that's okay - we'll migrate during finalize
|
|
152
|
-
2. **During Finalize:** ✅ **IMPLEMENTED**
|
|
153
|
-
- API call to eToro returns `realCID` in the response schema
|
|
154
|
-
- Store in new location: `signedInUsers/{realCID}/verification` (singleton document)
|
|
155
|
-
- Also update legacy location for backward compatibility
|
|
156
|
-
- Store user mapping: `signedInUsers/{realCID}` → `{ etoroCID: realCID, username, ... }` ✅ **IMPLEMENTED**
|
|
157
|
-
3. **Read:** Try new structure first (using CID), fallback to legacy (using username)
|
|
158
|
-
|
|
159
|
-
**Implementation Notes:**
|
|
160
|
-
- The eToro API response during `finalizeVerification()` includes:
|
|
161
|
-
- `realCID`: The eToro CID we want to use
|
|
162
|
-
- `gcid`: Group CID (may be different)
|
|
163
|
-
- `username`: Username
|
|
164
|
-
- `aboutMeShort`: Contains the OTP code
|
|
165
|
-
- We can use `realCID` immediately during finalization
|
|
166
|
-
- Store both CID and username in the verification document for lookup flexibility
|
|
167
|
-
|
|
168
|
-
---
|
|
169
|
-
|
|
170
|
-
### 6. User Watchlists ✅ **COMPLETED**
|
|
171
|
-
|
|
172
|
-
**Current:**
|
|
173
|
-
- `watchlists/{userCid}/lists/{watchlistId}` ✅ **Already using CID!**
|
|
174
|
-
- `public_watchlists/{watchlistId}` (for public watchlists) ✅ **Already correct!**
|
|
175
|
-
|
|
176
|
-
**New (Registry):**
|
|
177
|
-
- `signedInUsers/{cid}/watchlists/{watchlistId}` (private watchlists) ✅ **IMPLEMENTED**
|
|
178
|
-
- `public_watchlists/{watchlistId}` (public watchlists) ✅ **No change needed**
|
|
179
|
-
|
|
180
|
-
**API Endpoints Affected:**
|
|
181
|
-
- `GET /user/me/watchlists` - `getUserWatchlists()` in `watchlist_helpers.js` ✅ **UPDATED**
|
|
182
|
-
- `GET /user/me/watchlists/:id` - `getWatchlist()` in `watchlist_helpers.js` ✅ **UPDATED**
|
|
183
|
-
- `POST /user/me/watchlists` - `createWatchlist()` in `watchlist_helpers.js` ✅ **UPDATED**
|
|
184
|
-
- `PUT /user/me/watchlists/:id` - `updateWatchlistById()` in `watchlist_helpers.js` ✅ **UPDATED**
|
|
185
|
-
- `DELETE /user/me/watchlists/:id` - `deleteWatchlist()` in `watchlist_helpers.js` ✅ **UPDATED**
|
|
186
|
-
- `POST /user/me/watchlists/:id/copy` - `copyWatchlist()` in `watchlist_helpers.js` (uses same write logic)
|
|
187
|
-
- `POST /user/me/watchlists/:id/publish` - `publishWatchlistVersion()` in `watchlist_helpers.js` (uses public_watchlists)
|
|
188
|
-
- `GET /user/public-watchlists` - `getPublicWatchlists()` in `watchlist_helpers.js` (uses public_watchlists)
|
|
189
|
-
|
|
190
|
-
**Migration Strategy:**
|
|
191
|
-
1. ✅ **Private Watchlists:** Migrated from `watchlists/{cid}/lists` to `signedInUsers/{cid}/watchlists`
|
|
192
|
-
2. ✅ **Public Watchlists:** Keep in separate collection (already correct)
|
|
193
|
-
3. ✅ **Read:** Try new structure first, fallback to legacy
|
|
194
|
-
4. ✅ **Write:** Write to both locations during migration period
|
|
195
|
-
|
|
196
|
-
---
|
|
197
|
-
|
|
198
|
-
### 7. User Sync Requests & Status ✅ **COMPLETED**
|
|
199
|
-
|
|
200
|
-
**Current:**
|
|
201
|
-
- `user_sync_requests/{cid}/requests/{requestId}` (history)
|
|
202
|
-
- `user_sync_requests/{cid}/global/latest` (singleton)
|
|
203
|
-
|
|
204
|
-
**New (Registry):**
|
|
205
|
-
- `signedInUsers/{cid}/syncStatus` (singleton) ✅ **IMPLEMENTED**
|
|
206
|
-
- `signedInUsers/{cid}/syncRequests/{requestId}` (history) ✅ **IMPLEMENTED**
|
|
207
|
-
|
|
208
|
-
**API Endpoints Affected:**
|
|
209
|
-
- `POST /user/:userCid/sync` - `requestUserSync()` in `user_sync_helpers.js` ✅ **UPDATED**
|
|
210
|
-
- `GET /user/:userCid/sync-status` - `getUserSyncStatus()` in `user_sync_helpers.js` ✅ **UPDATED**
|
|
211
|
-
|
|
212
|
-
**Migration Strategy:**
|
|
213
|
-
1. ✅ **Write:** Write to both locations during migration
|
|
214
|
-
2. ✅ **Read:** Try new structure first, fallback to legacy
|
|
215
|
-
3. **Note:** Task engine already writes to new location, so API should read from there
|
|
216
|
-
|
|
217
|
-
---
|
|
218
|
-
|
|
219
|
-
### 8. Alert Subscriptions ✅ **COMPLETED**
|
|
220
|
-
|
|
221
|
-
**Current (Actual paths in code):**
|
|
222
|
-
- `watchlist_subscriptions/{userCid}/alerts/{piCid}`
|
|
223
|
-
|
|
224
|
-
**New (Registry - Dual Structure):**
|
|
225
|
-
- **Per-User Subscriptions:** `signedInUsers/{cid}/subscriptions/{piCid}` (global subscriptions, not tied to a watchlist) ✅ **IMPLEMENTED**
|
|
226
|
-
- **Per-Watchlist Subscriptions:** `signedInUsers/{cid}/watchlists/{watchlistId}/subscriptions/{piCid}` (subscriptions for a PI within a specific watchlist) ✅ **IMPLEMENTED**
|
|
227
|
-
|
|
228
|
-
**API Endpoints Affected:**
|
|
229
|
-
- `POST /user/me/subscriptions` - `subscribeToAlerts()` in `subscription_helpers.js` ✅ **UPDATED**
|
|
230
|
-
- `GET /user/me/subscriptions` - `getUserSubscriptions()` in `subscription_helpers.js` ✅ **UPDATED**
|
|
231
|
-
- `PUT /user/me/subscriptions/:piCid` - `updateSubscription()` in `subscription_helpers.js` ✅ **UPDATED**
|
|
232
|
-
- `DELETE /user/me/subscriptions/:piCid` - `unsubscribeFromAlerts()` in `subscription_helpers.js` ✅ **UPDATED**
|
|
233
|
-
- `POST /user/me/watchlists/:id/subscribe-all` - `subscribeToWatchlist()` in `subscription_helpers.js` ✅ **UPDATED**
|
|
234
|
-
|
|
235
|
-
**Migration Strategy:**
|
|
236
|
-
1. ✅ **Dual Structure:**
|
|
237
|
-
- If subscription has `watchlistId`, store in: `signedInUsers/{cid}/watchlists/{watchlistId}/subscriptions/{piCid}`
|
|
238
|
-
- If subscription is global (no watchlistId), store in: `signedInUsers/{cid}/subscriptions/{piCid}`
|
|
239
|
-
2. ✅ **Read:**
|
|
240
|
-
- For watchlist-specific: Read from `signedInUsers/{cid}/watchlists/{watchlistId}/subscriptions/{piCid}`
|
|
241
|
-
- For global: Read from `signedInUsers/{cid}/subscriptions/{piCid}`
|
|
242
|
-
- For "all subscriptions": Read from both locations and merge
|
|
243
|
-
3. ✅ **Write:** Write to both new structure and legacy during migration period
|
|
244
|
-
4. **Backward Compatibility:** Legacy structure `watchlist_subscriptions/{userCid}/alerts/{piCid}` can be migrated by checking if `watchlistId` exists in the subscription data
|
|
245
|
-
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
### 9. Popular Investor Data ✅ **COMPLETED**
|
|
249
|
-
|
|
250
|
-
**Current (Actual paths in code):**
|
|
251
|
-
- `pi_fetch_requests/{piCid}/requests/{requestId}` ⚠️ **Different from registry**
|
|
252
|
-
- `pi_fetch_requests/{piCid}/user_requests/{userCid}` ⚠️ **Different from registry**
|
|
253
|
-
- `pi_fetch_requests/{piCid}/global/latest` ⚠️ **Different from registry**
|
|
254
|
-
- `pi_reviews/{reviewId}` (flat collection, reviewId = `{userCid}_{piCid}`) ⚠️ **Different from registry**
|
|
255
|
-
- `profile_views/{piCid}_{date}` (flat collection with compound key) ⚠️ **Different from registry**
|
|
256
|
-
- `profile_views/individual_views/views/{individualViewId}` ⚠️ **Different from registry**
|
|
257
|
-
|
|
258
|
-
**New (Registry):**
|
|
259
|
-
- `popularInvestors/{piCid}/fetchRequests/{requestId}` ✅ **IMPLEMENTED**
|
|
260
|
-
- `popularInvestors/{piCid}/fetchStatus` (singleton) ✅ **IMPLEMENTED**
|
|
261
|
-
- `popularInvestors/{piCid}/userFetchRequests/{userCid}` ✅ **IMPLEMENTED** (for user rate limits, added to registry)
|
|
262
|
-
- `popularInvestors/{piCid}/reviews/{reviewId}` ✅ **IMPLEMENTED**
|
|
263
|
-
- `popularInvestors/{piCid}/profileViews/{date}` ✅ **IMPLEMENTED**
|
|
264
|
-
- `popularInvestors/{piCid}/views/{viewId}` ✅ **IMPLEMENTED**
|
|
265
|
-
|
|
266
|
-
**API Endpoints Affected:**
|
|
267
|
-
- `POST /user/pi/:piCid/request-fetch` - `requestPiFetch()` in `on_demand_fetch_helpers.js` ✅ **UPDATED**
|
|
268
|
-
- `GET /user/pi/:piCid/fetch-status` - `getPiFetchStatus()` in `on_demand_fetch_helpers.js` ✅ **UPDATED**
|
|
269
|
-
- `POST /user/review` - `submitReview()` in `review_helpers.js` ✅ **UPDATED**
|
|
270
|
-
- `GET /user/reviews/:piCid` - `getReviews()` in `review_helpers.js` ✅ **UPDATED**
|
|
271
|
-
- `GET /user/me/review/:piCid` - `getUserReview()` in `review_helpers.js` ✅ **UPDATED**
|
|
272
|
-
- `POST /user/pi/:piCid/track-view` - `trackProfileView()` in `data_helpers.js` ✅ **UPDATED**
|
|
273
|
-
- `GET /user/me/pi-personalized-metrics` - `getSignedInUserPIPersonalizedMetrics()` in `data_helpers.js` (reads profile views)
|
|
274
|
-
|
|
275
|
-
**Migration Strategy:**
|
|
276
|
-
1. ✅ **Fetch Requests:** Migrated from `pi_fetch_requests/{piCid}/requests` to `popularInvestors/{piCid}/fetchRequests`
|
|
277
|
-
2. ✅ **Fetch Status:** Migrated from `pi_fetch_requests/{piCid}/global/latest` to `popularInvestors/{piCid}/fetchStatus`
|
|
278
|
-
3. ✅ **User Fetch Requests:** Migrated from `pi_fetch_requests/{piCid}/user_requests/{userCid}` to `popularInvestors/{piCid}/userFetchRequests/{userCid}`
|
|
279
|
-
4. ✅ **Reviews:** Migrated from flat `pi_reviews/{reviewId}` to `popularInvestors/{piCid}/reviews/{reviewId}`
|
|
280
|
-
- **Solution:** Keep reviewId as `{userCid}_{piCid}`, but store under PI's subcollection
|
|
281
|
-
5. ✅ **Profile Views:** Migrated
|
|
282
|
-
- From `profile_views/{piCid}_{date}` to `popularInvestors/{piCid}/profileViews/{date}`
|
|
283
|
-
- From `profile_views/individual_views/views/{viewId}` to `popularInvestors/{piCid}/views/{viewId}`
|
|
284
|
-
- **Solution:** Parse compound key to extract date, store under PI's subcollection
|
|
285
|
-
6. ✅ **Read:** Try new structure first, fallback to legacy
|
|
286
|
-
7. ✅ **Write:** Write to both locations during migration period
|
|
287
|
-
|
|
288
|
-
---
|
|
289
|
-
|
|
290
|
-
## Implementation Priority
|
|
291
|
-
|
|
292
|
-
### Phase 1: Low-Risk, High-Value (Start Here) ✅ **COMPLETED**
|
|
293
|
-
1. ✅ **User Social Posts** - Simple path change, already using CID
|
|
294
|
-
2. ✅ **User Sync Requests** - Task engine already writes to new location
|
|
295
|
-
3. ⚠️ **User Notifications** - Update to use CID (add CID lookup helper) - Helper created, but notifications use Firebase UID for frontend compatibility
|
|
296
|
-
|
|
297
|
-
### Phase 2: Medium Complexity ✅ **COMPLETED**
|
|
298
|
-
5. ✅ **User Portfolio** - Needs fallback logic, but straightforward
|
|
299
|
-
6. ✅ **User Trade History** - Similar to portfolio, used internally
|
|
300
|
-
|
|
301
|
-
### Phase 3: Higher Complexity ✅ **COMPLETED**
|
|
302
|
-
7. ✅ **User Watchlists** - Multiple endpoints, but clear migration path
|
|
303
|
-
8. ✅ **User Verification** - CID available during finalize (from API response), migrate during finalization
|
|
304
|
-
9. ✅ **Popular Investor Data** - Multiple subcollections (fetch requests, reviews, profile views) need migration
|
|
305
|
-
10. ✅ **Alert Subscriptions** - Dual structure (per-user vs per-watchlist) implemented
|
|
306
|
-
|
|
307
|
-
---
|
|
308
|
-
|
|
309
|
-
## Helper Functions Needed
|
|
310
|
-
|
|
311
|
-
### 1. CID Lookup Helper ✅ **COMPLETED**
|
|
312
|
-
Helper to get CID from Firebase UID (for API endpoints that receive Firebase UID):
|
|
313
|
-
```javascript
|
|
314
|
-
async function getCidFromFirebaseUid(db, firebaseUid) {
|
|
315
|
-
const userDoc = await db.collection('signedInUsers').doc(firebaseUid).get();
|
|
316
|
-
if (!userDoc.exists) return null;
|
|
317
|
-
const data = userDoc.data();
|
|
318
|
-
return data.etoroCID || null;
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
✅ **IMPLEMENTED** in `collection_helpers.js`
|
|
322
|
-
|
|
323
|
-
### 2. Collection Path Resolver ✅ **COMPLETED**
|
|
324
|
-
Create a helper that uses `collectionRegistry` to resolve paths:
|
|
325
|
-
```javascript
|
|
326
|
-
function getUserCollectionPath(category, subcategory, params) {
|
|
327
|
-
const { collectionRegistry } = dependencies;
|
|
328
|
-
return collectionRegistry.getCollectionPath('signedInUsers', subcategory, params);
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
✅ **IMPLEMENTED** in `collection_helpers.js` as `getCollectionPath()`
|
|
332
|
-
|
|
333
|
-
### 3. Dual Read Helper ✅ **COMPLETED**
|
|
334
|
-
Helper to read from new structure with legacy fallback:
|
|
335
|
-
```javascript
|
|
336
|
-
async function readWithFallback(newPath, legacyPath, db) {
|
|
337
|
-
// Try new structure first
|
|
338
|
-
const newDoc = await db.doc(newPath).get();
|
|
339
|
-
if (newDoc.exists) return newDoc.data();
|
|
340
|
-
|
|
341
|
-
// Fallback to legacy
|
|
342
|
-
const legacyDoc = await db.doc(legacyPath).get();
|
|
343
|
-
if (legacyDoc.exists) return legacyDoc.data();
|
|
344
|
-
|
|
345
|
-
return null;
|
|
346
|
-
}
|
|
347
|
-
```
|
|
348
|
-
✅ **IMPLEMENTED** in `collection_helpers.js`
|
|
349
|
-
|
|
350
|
-
### 4. Dual Write Helper ✅ **COMPLETED**
|
|
351
|
-
Helper to write to both locations during migration:
|
|
352
|
-
```javascript
|
|
353
|
-
async function writeDual(newPath, legacyPath, data, db) {
|
|
354
|
-
const batch = db.batch();
|
|
355
|
-
batch.set(db.doc(newPath), data);
|
|
356
|
-
batch.set(db.doc(legacyPath), data);
|
|
357
|
-
await batch.commit();
|
|
358
|
-
}
|
|
359
|
-
```
|
|
360
|
-
✅ **IMPLEMENTED** in `collection_helpers.js`
|
|
361
|
-
|
|
362
|
-
---
|
|
363
|
-
|
|
364
|
-
## Migration Checklist
|
|
365
|
-
|
|
366
|
-
### Immediate Actions ✅ **ALL COMPLETED**
|
|
367
|
-
- [x] Inject `collectionRegistry` into API dependencies ✅ **COMPLETED** (in `index.js` line 50)
|
|
368
|
-
- [x] Create helper functions for path resolution and dual read/write ✅ **COMPLETED** (`collection_helpers.js`)
|
|
369
|
-
- [x] Update `getUserSocialPosts()` to use new path ✅ **COMPLETED**
|
|
370
|
-
- [x] Update `getUserPortfolio()` to use new path with fallback ✅ **COMPLETED**
|
|
371
|
-
- [x] Update sync request/status endpoints to use new paths ✅ **COMPLETED**
|
|
372
|
-
|
|
373
|
-
### Short-Term (Next Sprint) ✅ **ALL COMPLETED**
|
|
374
|
-
- [x] Update watchlist endpoints to use new paths ✅ **COMPLETED**
|
|
375
|
-
- [x] Update verification endpoints (handle CID lookup challenge) ✅ **COMPLETED**
|
|
376
|
-
- [x] Update Popular Investor data endpoints (fetch requests, reviews, profile views) ✅ **COMPLETED**
|
|
377
|
-
- [x] Update subscription endpoints (dual structure: per-user and per-watchlist) ✅ **COMPLETED**
|
|
378
|
-
- [ ] Add migration logging to track usage of legacy vs new paths (optional enhancement)
|
|
379
|
-
|
|
380
|
-
### Long-Term (Post-Migration)
|
|
381
|
-
- [ ] Remove legacy path fallbacks once migration is complete (after 1-2 month migration period)
|
|
382
|
-
- [ ] Create data migration script to move existing data to new structure
|
|
383
|
-
- [ ] Update documentation
|
|
384
|
-
|
|
385
|
-
---
|
|
386
|
-
|
|
387
|
-
## Testing Strategy
|
|
388
|
-
|
|
389
|
-
1. **Unit Tests:** Test each helper function with both new and legacy paths
|
|
390
|
-
2. **Integration Tests:** Test API endpoints with:
|
|
391
|
-
- Data only in new structure
|
|
392
|
-
- Data only in legacy structure
|
|
393
|
-
- Data in both (should prefer new)
|
|
394
|
-
- No data (should return 404)
|
|
395
|
-
3. **Migration Tests:** Verify dual writes work correctly
|
|
396
|
-
4. **Backward Compatibility:** Ensure existing users can still access their data
|
|
397
|
-
|
|
398
|
-
---
|
|
399
|
-
|
|
400
|
-
## Notes
|
|
401
|
-
|
|
402
|
-
- **CID Consistency:** Use eToro CID (`realCID`) everywhere for user identification. Firebase UID is only used for authentication, but all data paths should use CID.
|
|
403
|
-
- **CID Lookup:** When frontend provides Firebase UID, API should look up CID from `signedInUsers/{firebaseUid}` mapping document.
|
|
404
|
-
- **Verification:** CID is available immediately during `finalizeVerification()` from the eToro API response (`realCID` field).
|
|
405
|
-
- **Post IDs:** Social posts already use post IDs correctly
|
|
406
|
-
- **Backward Compatibility:** Maintain legacy paths during migration period (estimate 1-2 months)
|
|
407
|
-
- **Data Migration:** Will need a separate script to migrate existing data to new structure
|
|
408
|
-
- **User Mapping:** The `signedInUsers` collection should maintain a mapping: `signedInUsers/{firebaseUid}` → `{ etoroCID, etoroUsername, ... }` for CID lookup
|
|
409
|
-
|
|
410
|
-
## Path Structure Verification
|
|
411
|
-
|
|
412
|
-
All implemented paths match the `collection_registry.js` definitions:
|
|
413
|
-
|
|
414
|
-
### Signed-In Users (User-Centric)
|
|
415
|
-
- ✅ `signedInUsers/{cid}/portfolio/latest` - matches registry
|
|
416
|
-
- ✅ `signedInUsers/{cid}/tradeHistory/latest` - matches registry
|
|
417
|
-
- ✅ `signedInUsers/{cid}/posts/{postId}` - matches registry
|
|
418
|
-
- ✅ `signedInUsers/{cid}/verification` - matches registry (singleton)
|
|
419
|
-
- ✅ `signedInUsers/{cid}/watchlists/{watchlistId}` - matches registry
|
|
420
|
-
- ✅ `signedInUsers/{cid}/syncRequests/{requestId}` - matches registry
|
|
421
|
-
- ✅ `signedInUsers/{cid}/syncStatus` - matches registry (singleton)
|
|
422
|
-
- ✅ `signedInUsers/{cid}/subscriptions/{piCid}` - matches registry
|
|
423
|
-
- ✅ `signedInUsers/{cid}/watchlists/{watchlistId}/subscriptions/{piCid}` - matches registry
|
|
424
|
-
|
|
425
|
-
### Popular Investors
|
|
426
|
-
- ✅ `popularInvestors/{piCid}/fetchRequests/{requestId}` - matches registry
|
|
427
|
-
- ✅ `popularInvestors/{piCid}/fetchStatus` - matches registry (singleton)
|
|
428
|
-
- ✅ `popularInvestors/{piCid}/userFetchRequests/{userCid}` - matches registry (added during migration)
|
|
429
|
-
- ✅ `popularInvestors/{piCid}/reviews/{reviewId}` - matches registry
|
|
430
|
-
- ✅ `popularInvestors/{piCid}/profileViews/{date}` - matches registry
|
|
431
|
-
- ✅ `popularInvestors/{piCid}/views/{viewId}` - matches registry
|
|
432
|
-
|
|
433
|
-
### Root Data (Date-Based)
|
|
434
|
-
- ✅ `SignedInUserPortfolioData/{date}/{cid}` - matches registry
|
|
435
|
-
- ✅ `SignedInUserTradeHistoryData/{date}/{cid}` - matches registry
|
|
436
|
-
- ✅ `SignedInUserSocialPostData/{date}/{cid}` - matches registry
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Profile Page Fallback Conditions
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This document explains when and why the profile page uses fallback mode instead of computation data.
|
|
6
|
-
|
|
7
|
-
## Data Storage Locations
|
|
8
|
-
|
|
9
|
-
### Signed-In User Computations
|
|
10
|
-
- **Category**: `popular-investor` (NOT `signed_in_user`)
|
|
11
|
-
- **Reason**: ResultCommitter ignores category metadata when computation is in a non-core folder
|
|
12
|
-
- **Computation**: `SignedInUserProfileMetrics` is in `calculations/popular-investor/` folder
|
|
13
|
-
- **Path**: `/unified_insights/{date}/results/popular-investor/computations/SignedInUserProfileMetrics`
|
|
14
|
-
|
|
15
|
-
### Signed-In User Raw Data
|
|
16
|
-
- **Portfolio**: `signed_in_users/{blockId}/snapshots/{date}/parts/part_*`
|
|
17
|
-
- **History**: `signed_in_user_history/{blockId}/snapshots/{date}/parts/part_*` (or `signed_in_users_history` depending on config)
|
|
18
|
-
- **Social**: `signed_in_users_social/{cid}/posts/{postId}`
|
|
19
|
-
|
|
20
|
-
## Fallback Conditions
|
|
21
|
-
|
|
22
|
-
### Frontend Fallback Logic (UserProfile.tsx)
|
|
23
|
-
|
|
24
|
-
The profile page uses fallback mode when:
|
|
25
|
-
|
|
26
|
-
1. **Computation Not Found**:
|
|
27
|
-
- API call to `/user/me/computations?computation=SignedInUserProfileMetrics` returns empty `data: {}`
|
|
28
|
-
- OR the computation exists but doesn't contain data for the user's CID
|
|
29
|
-
|
|
30
|
-
2. **API Error**:
|
|
31
|
-
- Any error fetching the computation (network error, 500, etc.)
|
|
32
|
-
|
|
33
|
-
3. **Data Structure Issues**:
|
|
34
|
-
- Computation exists but `metricsResponse.data[latestDate]?.SignedInUserProfileMetrics` is undefined/null
|
|
35
|
-
|
|
36
|
-
### Backend Fallback Logic (getUserComputations)
|
|
37
|
-
|
|
38
|
-
The API returns `isFallback: false` but `data: {}` when:
|
|
39
|
-
|
|
40
|
-
1. **Wrong Category Lookup** (FIXED):
|
|
41
|
-
- Was looking in `signed_in_user` category
|
|
42
|
-
- Should look in `popular-investor` category
|
|
43
|
-
|
|
44
|
-
2. **No Data for User**:
|
|
45
|
-
- Computation document exists but doesn't contain `data[String(effectiveCid)]`
|
|
46
|
-
- This can happen if:
|
|
47
|
-
- Computation ran but user wasn't included (shouldn't happen with targetCid optimization)
|
|
48
|
-
- Data is sharded and shard doesn't contain user's data
|
|
49
|
-
- Data exists but in wrong format
|
|
50
|
-
|
|
51
|
-
3. **Date Mismatch**:
|
|
52
|
-
- Computation exists for different date than requested
|
|
53
|
-
- `mode=latest` tries to find latest date, but if none found, returns empty
|
|
54
|
-
|
|
55
|
-
## Current Issue
|
|
56
|
-
|
|
57
|
-
The user reported:
|
|
58
|
-
- API returns `"isFallback": false, "data": {}`
|
|
59
|
-
- Profile page shows fallback mode
|
|
60
|
-
- Computation exists at `/unified_insights/2025-12-29/results/popular-investor/computations/SignedInUserProfileMetrics/_shards/shard_0`
|
|
61
|
-
|
|
62
|
-
**Root Cause**: The `getUserComputations` endpoint was looking in the wrong category (`signed_in_user` instead of `popular-investor`).
|
|
63
|
-
|
|
64
|
-
**Fix Applied**: Updated `getUserComputations` to look in `popular-investor` category for `SignedInUserProfileMetrics`.
|
|
65
|
-
|
|
66
|
-
## Verification Steps
|
|
67
|
-
|
|
68
|
-
1. Check computation exists:
|
|
69
|
-
```
|
|
70
|
-
/unified_insights/2025-12-29/results/popular-investor/computations/SignedInUserProfileMetrics
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
2. Check if data is sharded:
|
|
74
|
-
- If `_sharded: true`, check `_shards` subcollection
|
|
75
|
-
- Merge all shards to get full data
|
|
76
|
-
|
|
77
|
-
3. Check if user's CID exists in data:
|
|
78
|
-
- Data structure: `{ "29312236": { ...metrics... } }`
|
|
79
|
-
- Must use `String(cid)` as key
|
|
80
|
-
|
|
81
|
-
4. Check API response:
|
|
82
|
-
- Should return `data: { "2025-12-29": { "SignedInUserProfileMetrics": { ... } } }`
|
|
83
|
-
- If empty, check logs for why lookup failed
|
|
84
|
-
|
|
85
|
-
## History Data Storage
|
|
86
|
-
|
|
87
|
-
Signed-in user trade history is stored in:
|
|
88
|
-
- Collection: `signed_in_user_history` (or `signed_in_users_history` depending on config)
|
|
89
|
-
- Path: `{collection}/{blockId}/snapshots/{date}/parts/part_*`
|
|
90
|
-
- Block ID: Typically `19M` (canary block)
|
|
91
|
-
|
|
92
|
-
The task engine stores history via:
|
|
93
|
-
```javascript
|
|
94
|
-
await batchManager.addToTradingHistoryBatch(String(cid), blockId, today, historyData, 'signed_in_user');
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
This uses `getHistoryCollection('signed_in_user')` which returns `signedInHistory` collection.
|
|
98
|
-
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# Signed-In User History Storage Location
|
|
2
|
-
|
|
3
|
-
## Current Issue
|
|
4
|
-
|
|
5
|
-
History data is being stored in the **wrong collection** because `FIRESTORE_COLLECTION_SIGNED_IN_HISTORY` is not defined in the task engine config, causing it to fall back to `NormalUserTradeHistory`.
|
|
6
|
-
|
|
7
|
-
## Storage Path Structure
|
|
8
|
-
|
|
9
|
-
For signed-in users, history data should be stored at:
|
|
10
|
-
```
|
|
11
|
-
{signed_in_user_history}/{blockId}/snapshots/{date}/parts/part_{shardIndex}
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Where:
|
|
15
|
-
- `signed_in_user_history` = Collection name (default: `signed_in_user_history`)
|
|
16
|
-
- `blockId` = `'19M'` (canary block ID)
|
|
17
|
-
- `date` = Date string in format `YYYY-MM-DD` (e.g., `2025-12-29`)
|
|
18
|
-
- `shardIndex` = `cid % TOTAL_SHARDS` (modulo sharding for even distribution)
|
|
19
|
-
|
|
20
|
-
## Example Path
|
|
21
|
-
|
|
22
|
-
For user CID `29312236` on date `2025-12-29`:
|
|
23
|
-
```
|
|
24
|
-
signed_in_user_history/19M/snapshots/2025-12-29/parts/part_{shardIndex}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Where `shardIndex = 29312236 % TOTAL_SHARDS` (typically 7 shards, so `29312236 % 7 = 1`)
|
|
28
|
-
|
|
29
|
-
## Fix Applied
|
|
30
|
-
|
|
31
|
-
Added `FIRESTORE_COLLECTION_SIGNED_IN_HISTORY` to `taskEngine_config.js`:
|
|
32
|
-
```javascript
|
|
33
|
-
FIRESTORE_COLLECTION_SIGNED_IN_HISTORY: getEnvVar('FIRESTORE_COLLECTION_SIGNED_IN_HISTORY', 'signed_in_user_history'),
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Before Fix
|
|
37
|
-
|
|
38
|
-
Without this config, the batch manager was using:
|
|
39
|
-
- `config.FIRESTORE_COLLECTION_SIGNED_IN_HISTORY` = `undefined`
|
|
40
|
-
- Fallback: `config.FIRESTORE_COLLECTION_NORMAL_HISTORY` = `'NormalUserTradeHistory'`
|
|
41
|
-
|
|
42
|
-
So data was being stored at:
|
|
43
|
-
```
|
|
44
|
-
NormalUserTradeHistory/19M/snapshots/2025-12-29/parts/part_{shardIndex}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## After Fix
|
|
48
|
-
|
|
49
|
-
With the config added, data will be stored at:
|
|
50
|
-
```
|
|
51
|
-
signed_in_user_history/19M/snapshots/2025-12-29/parts/part_{shardIndex}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Verification
|
|
55
|
-
|
|
56
|
-
To verify history data exists for a user:
|
|
57
|
-
1. Calculate shard index: `userCid % 7` (or whatever TOTAL_SHARDS is)
|
|
58
|
-
2. Check path: `signed_in_user_history/19M/snapshots/2025-12-29/parts/part_{shardIndex}`
|
|
59
|
-
3. Look for user's CID as a key in the document: `{ "29312236": { ...historyData... } }`
|
|
60
|
-
|
|
61
|
-
## Related Collections
|
|
62
|
-
|
|
63
|
-
- **Portfolio**: `signed_in_users/19M/snapshots/{date}/parts/part_{shardIndex}`
|
|
64
|
-
- **History**: `signed_in_user_history/19M/snapshots/{date}/parts/part_{shardIndex}` (FIXED)
|
|
65
|
-
- **Social**: `signed_in_users_social/{cid}/posts/{postId}`
|
|
66
|
-
|