kamau1 commited on
Commit
3e9b945
·
1 Parent(s): a37b051

Add dedicated /users/me document and profile photo endpoints to avoid UUID parsing errors

Browse files
docs/devlogs/browser/browserconsole.txt CHANGED
@@ -32,82 +32,24 @@ flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
32
  workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
33
  flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
34
  performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
35
- core.ts:167 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (1.12s)
36
  core.ts:167 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences
37
- core.ts:167 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences → 200 (461ms)
38
- chunk-276SZO74.js?v=4b4f0c17:521 Warning: Cannot update a component (`ForwardRef`) while rendering a different component (`ForwardRef`). To locate the bad setState() call inside `ForwardRef`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
39
- at http://localhost:8080/node_modules/.vite/deps/sonner.js?v=4b4f0c17:269:17
40
- at Toaster (http://localhost:8080/src/components/ui/sonner.tsx:24:23)
41
- at Provider (http://localhost:8080/node_modules/.vite/deps/chunk-3RXG37ZK.js?v=4b4f0c17:38:15)
42
- at TooltipProvider (http://localhost:8080/node_modules/.vite/deps/@radix-ui_react-tooltip.js?v=4b4f0c17:65:5)
43
- at ThemeProvider (http://localhost:8080/src/contexts/ThemeProvider.tsx:29:33)
44
- at UserPreferencesProvider (http://localhost:8080/src/contexts/UserPreferencesContext.tsx:28:43)
45
- at QueryClientProvider (http://localhost:8080/node_modules/.vite/deps/@tanstack_react-query.js?v=4b4f0c17:2934:3)
46
- at App (http://localhost:8080/src/App.tsx?t=1764660642977:171:35)
47
- printWarning @ chunk-276SZO74.js?v=4b4f0c17:521
48
- error @ chunk-276SZO74.js?v=4b4f0c17:505
49
- warnAboutRenderPhaseUpdatesInDEV @ chunk-276SZO74.js?v=4b4f0c17:19793
50
- scheduleUpdateOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18546
51
- dispatchSetState @ chunk-276SZO74.js?v=4b4f0c17:12403
52
- (anonymous) @ sonner.js?v=4b4f0c17:277
53
- (anonymous) @ sonner.js?v=4b4f0c17:68
54
- dismiss @ sonner.js?v=4b4f0c17:68
55
- (anonymous) @ sonner.js?v=4b4f0c17:272
56
- basicStateReducer @ chunk-276SZO74.js?v=4b4f0c17:11703
57
- updateReducer @ chunk-276SZO74.js?v=4b4f0c17:11794
58
- updateState @ chunk-276SZO74.js?v=4b4f0c17:12021
59
- useState @ chunk-276SZO74.js?v=4b4f0c17:12753
60
- useState @ chunk-ZMLY2J2T.js?v=4b4f0c17:1066
61
- (anonymous) @ sonner.js?v=4b4f0c17:269
62
- renderWithHooks @ chunk-276SZO74.js?v=4b4f0c17:11548
63
- updateForwardRef @ chunk-276SZO74.js?v=4b4f0c17:14325
64
- beginWork @ chunk-276SZO74.js?v=4b4f0c17:15946
65
- beginWork$1 @ chunk-276SZO74.js?v=4b4f0c17:19753
66
- performUnitOfWork @ chunk-276SZO74.js?v=4b4f0c17:19198
67
- workLoopSync @ chunk-276SZO74.js?v=4b4f0c17:19137
68
- renderRootSync @ chunk-276SZO74.js?v=4b4f0c17:19116
69
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18678
70
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
71
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
72
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
73
- chunk-24BRHPTI.js?v=4b4f0c17:42 Select is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
74
- (anonymous) @ chunk-24BRHPTI.js?v=4b4f0c17:42
75
- commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
76
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
77
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
78
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=4b4f0c17:18119
79
- commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
80
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
81
- flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
82
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18868
83
- flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
84
- commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19432
85
- commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
86
- finishConcurrentRender @ chunk-276SZO74.js?v=4b4f0c17:18805
87
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18718
88
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
89
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
90
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
91
- chunk-24BRHPTI.js?v=4b4f0c17:42 Select is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
92
- (anonymous) @ chunk-24BRHPTI.js?v=4b4f0c17:42
93
- commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
94
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
95
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
96
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=4b4f0c17:18119
97
- commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
98
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
99
- flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
100
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18868
101
- flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
102
- commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19432
103
- commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
104
- finishConcurrentRender @ chunk-276SZO74.js?v=4b4f0c17:18805
105
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18718
106
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
107
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
108
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
109
- chunk-24BRHPTI.js?v=4b4f0c17:42 Select is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
110
- (anonymous) @ chunk-24BRHPTI.js?v=4b4f0c17:42
111
  commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
112
  commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
113
  commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
@@ -115,35 +57,32 @@ commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=4b4f0c17:18119
115
  commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
116
  flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
117
  flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
118
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18868
119
- flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
120
- commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19432
121
  commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
122
- finishConcurrentRender @ chunk-276SZO74.js?v=4b4f0c17:18805
123
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18718
124
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
125
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
126
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
127
- chunk-24BRHPTI.js?v=4b4f0c17:42 Select is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
128
- (anonymous) @ chunk-24BRHPTI.js?v=4b4f0c17:42
129
- commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
130
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
131
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
132
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=4b4f0c17:18119
133
- commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
134
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
135
- flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
136
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18868
137
  flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
138
- commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19432
139
- commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
140
- finishConcurrentRender @ chunk-276SZO74.js?v=4b4f0c17:18805
141
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18718
142
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
143
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
144
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
145
- chunk-24BRHPTI.js?v=4b4f0c17:42 Select is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
146
- (anonymous) @ chunk-24BRHPTI.js?v=4b4f0c17:42
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
148
  commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
149
  commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
@@ -151,103 +90,9 @@ commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=4b4f0c17:18119
151
  commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
152
  flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
153
  flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
154
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18868
155
- flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
156
- commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19432
157
  commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
158
- finishConcurrentRender @ chunk-276SZO74.js?v=4b4f0c17:18805
159
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18718
160
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
161
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
162
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
163
- chunk-24BRHPTI.js?v=4b4f0c17:42 Select is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
164
- (anonymous) @ chunk-24BRHPTI.js?v=4b4f0c17:42
165
- commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
166
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
167
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
168
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=4b4f0c17:18119
169
- commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
170
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
171
- flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
172
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18868
173
  flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
174
- commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19432
175
- commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
176
- finishConcurrentRender @ chunk-276SZO74.js?v=4b4f0c17:18805
177
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18718
178
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
179
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
180
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
181
- chunk-24BRHPTI.js?v=4b4f0c17:42 Select is changing from uncontrolled to controlled. Components should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled value for the lifetime of the component.
182
- (anonymous) @ chunk-24BRHPTI.js?v=4b4f0c17:42
183
- commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
184
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
185
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
186
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=4b4f0c17:18119
187
- commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
188
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
189
- flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
190
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18868
191
- flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
192
- commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19432
193
- commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
194
- finishConcurrentRender @ chunk-276SZO74.js?v=4b4f0c17:18805
195
- performConcurrentWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18718
196
- workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
197
- flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
198
- performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
199
- useUserProfile.ts:21 POST https://kamau1-swiftops-backend.hf.space/api/v1/financial-accounts/me 422 (Unprocessable Content)
200
- fetchWithAuth @ useUserProfile.ts:21
201
- mutationFn @ useUserProfile.ts:120
202
- fn @ @tanstack_react-query.js?v=4b4f0c17:1236
203
- run @ @tanstack_react-query.js?v=4b4f0c17:513
204
- start @ @tanstack_react-query.js?v=4b4f0c17:555
205
- execute @ @tanstack_react-query.js?v=4b4f0c17:1272
206
- await in execute
207
- mutate @ @tanstack_react-query.js?v=4b4f0c17:2692
208
- handleSubmit @ ManageAccountModal.tsx:75
209
- callCallback2 @ chunk-276SZO74.js?v=4b4f0c17:3674
210
- invokeGuardedCallbackDev @ chunk-276SZO74.js?v=4b4f0c17:3699
211
- invokeGuardedCallback @ chunk-276SZO74.js?v=4b4f0c17:3733
212
- invokeGuardedCallbackAndCatchFirstError @ chunk-276SZO74.js?v=4b4f0c17:3736
213
- executeDispatch @ chunk-276SZO74.js?v=4b4f0c17:7014
214
- processDispatchQueueItemsInOrder @ chunk-276SZO74.js?v=4b4f0c17:7034
215
- processDispatchQueue @ chunk-276SZO74.js?v=4b4f0c17:7043
216
- dispatchEventsForPlugins @ chunk-276SZO74.js?v=4b4f0c17:7051
217
- (anonymous) @ chunk-276SZO74.js?v=4b4f0c17:7174
218
- batchedUpdates$1 @ chunk-276SZO74.js?v=4b4f0c17:18913
219
- batchedUpdates @ chunk-276SZO74.js?v=4b4f0c17:3579
220
- dispatchEventForPluginEventSystem @ chunk-276SZO74.js?v=4b4f0c17:7173
221
- dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ chunk-276SZO74.js?v=4b4f0c17:5478
222
- dispatchEvent @ chunk-276SZO74.js?v=4b4f0c17:5472
223
- dispatchDiscreteEvent @ chunk-276SZO74.js?v=4b4f0c17:5449
224
- useUserProfile.ts:21 POST https://kamau1-swiftops-backend.hf.space/api/v1/financial-accounts/me 422 (Unprocessable Content)
225
- fetchWithAuth @ useUserProfile.ts:21
226
- mutationFn @ useUserProfile.ts:120
227
- fn @ @tanstack_react-query.js?v=4b4f0c17:1236
228
- run @ @tanstack_react-query.js?v=4b4f0c17:513
229
- (anonymous) @ @tanstack_react-query.js?v=4b4f0c17:538
230
- Promise.then
231
- (anonymous) @ @tanstack_react-query.js?v=4b4f0c17:534
232
- Promise.catch
233
- run @ @tanstack_react-query.js?v=4b4f0c17:517
234
- start @ @tanstack_react-query.js?v=4b4f0c17:555
235
- execute @ @tanstack_react-query.js?v=4b4f0c17:1272
236
- await in execute
237
- mutate @ @tanstack_react-query.js?v=4b4f0c17:2692
238
- handleSubmit @ ManageAccountModal.tsx:75
239
- callCallback2 @ chunk-276SZO74.js?v=4b4f0c17:3674
240
- invokeGuardedCallbackDev @ chunk-276SZO74.js?v=4b4f0c17:3699
241
- invokeGuardedCallback @ chunk-276SZO74.js?v=4b4f0c17:3733
242
- invokeGuardedCallbackAndCatchFirstError @ chunk-276SZO74.js?v=4b4f0c17:3736
243
- executeDispatch @ chunk-276SZO74.js?v=4b4f0c17:7014
244
- processDispatchQueueItemsInOrder @ chunk-276SZO74.js?v=4b4f0c17:7034
245
- processDispatchQueue @ chunk-276SZO74.js?v=4b4f0c17:7043
246
- dispatchEventsForPlugins @ chunk-276SZO74.js?v=4b4f0c17:7051
247
- (anonymous) @ chunk-276SZO74.js?v=4b4f0c17:7174
248
- batchedUpdates$1 @ chunk-276SZO74.js?v=4b4f0c17:18913
249
- batchedUpdates @ chunk-276SZO74.js?v=4b4f0c17:3579
250
- dispatchEventForPluginEventSystem @ chunk-276SZO74.js?v=4b4f0c17:7173
251
- dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ chunk-276SZO74.js?v=4b4f0c17:5478
252
- dispatchEvent @ chunk-276SZO74.js?v=4b4f0c17:5472
253
- dispatchDiscreteEvent @ chunk-276SZO74.js?v=4b4f0c17:5449
 
32
  workLoop @ chunk-276SZO74.js?v=4b4f0c17:197
33
  flushWork @ chunk-276SZO74.js?v=4b4f0c17:176
34
  performWorkUntilDeadline @ chunk-276SZO74.js?v=4b4f0c17:384
35
+ core.ts:167 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (1.51s)
36
  core.ts:167 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences
37
+ core.ts:167 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences → 200 (863ms)
38
+ core.ts:167 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/documents/users/me
39
+ api-client.ts:124 GET https://kamau1-swiftops-backend.hf.space/api/v1/documents/users/me 422 (Unprocessable Content)
40
+ request @ api-client.ts:124
41
+ get @ api-client.ts:190
42
+ getMyDocuments @ document.service.ts:8
43
+ queryFn @ useDocuments.ts:8
44
+ fetchFn @ @tanstack_react-query.js?v=4b4f0c17:881
45
+ run @ @tanstack_react-query.js?v=4b4f0c17:513
46
+ start @ @tanstack_react-query.js?v=4b4f0c17:555
47
+ fetch @ @tanstack_react-query.js?v=4b4f0c17:969
48
+ executeFetch_fn @ @tanstack_react-query.js?v=4b4f0c17:2280
49
+ onSubscribe @ @tanstack_react-query.js?v=4b4f0c17:1983
50
+ subscribe @ @tanstack_react-query.js?v=4b4f0c17:24
51
+ (anonymous) @ @tanstack_react-query.js?v=4b4f0c17:3147
52
+ subscribeToStore @ chunk-276SZO74.js?v=4b4f0c17:11984
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
54
  commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
55
  commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
 
57
  commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
58
  flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
59
  flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
60
+ commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19416
 
 
61
  commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
62
+ performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18895
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
64
+ (anonymous) @ chunk-276SZO74.js?v=4b4f0c17:18627
65
+ core.ts:167 GET https://kamau1-swiftops-backend.hf.space/api/v1/documents/users/me → 422 (358ms)
66
+ core.ts:167 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/documents/users/me
67
+ api-client.ts:124 GET https://kamau1-swiftops-backend.hf.space/api/v1/documents/users/me 422 (Unprocessable Content)
68
+ request @ api-client.ts:124
69
+ get @ api-client.ts:190
70
+ getMyDocuments @ document.service.ts:8
71
+ queryFn @ useDocuments.ts:8
72
+ fetchFn @ @tanstack_react-query.js?v=4b4f0c17:881
73
+ run @ @tanstack_react-query.js?v=4b4f0c17:513
74
+ (anonymous) @ @tanstack_react-query.js?v=4b4f0c17:538
75
+ Promise.then
76
+ (anonymous) @ @tanstack_react-query.js?v=4b4f0c17:534
77
+ Promise.catch
78
+ run @ @tanstack_react-query.js?v=4b4f0c17:517
79
+ start @ @tanstack_react-query.js?v=4b4f0c17:555
80
+ fetch @ @tanstack_react-query.js?v=4b4f0c17:969
81
+ executeFetch_fn @ @tanstack_react-query.js?v=4b4f0c17:2280
82
+ onSubscribe @ @tanstack_react-query.js?v=4b4f0c17:1983
83
+ subscribe @ @tanstack_react-query.js?v=4b4f0c17:24
84
+ (anonymous) @ @tanstack_react-query.js?v=4b4f0c17:3147
85
+ subscribeToStore @ chunk-276SZO74.js?v=4b4f0c17:11984
86
  commitHookEffectListMount @ chunk-276SZO74.js?v=4b4f0c17:16915
87
  commitPassiveMountOnFiber @ chunk-276SZO74.js?v=4b4f0c17:18156
88
  commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=4b4f0c17:18129
 
90
  commitPassiveMountEffects @ chunk-276SZO74.js?v=4b4f0c17:18109
91
  flushPassiveEffectsImpl @ chunk-276SZO74.js?v=4b4f0c17:19490
92
  flushPassiveEffects @ chunk-276SZO74.js?v=4b4f0c17:19447
93
+ commitRootImpl @ chunk-276SZO74.js?v=4b4f0c17:19416
 
 
94
  commitRoot @ chunk-276SZO74.js?v=4b4f0c17:19277
95
+ performSyncWorkOnRoot @ chunk-276SZO74.js?v=4b4f0c17:18895
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  flushSyncCallbacks @ chunk-276SZO74.js?v=4b4f0c17:9119
97
+ (anonymous) @ chunk-276SZO74.js?v=4b4f0c17:18627
98
+ core.ts:167 GET https://kamau1-swiftops-backend.hf.space/api/v1/documents/users/me → 422 (332ms)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/devlogs/server/runtimeerror.txt CHANGED
@@ -1,95 +1,51 @@
1
- ===== Application Startup at 2025-12-02 07:31:55 =====
2
 
3
  INFO: Started server process [7]
4
  INFO: Waiting for application startup.
5
- INFO: 2025-12-02T07:32:04 - app.main: ============================================================
6
- INFO: 2025-12-02T07:32:04 - app.main: 🚀 SwiftOps API v1.0.0 | PRODUCTION
7
- INFO: 2025-12-02T07:32:04 - app.main: 📊 Dashboard: Enabled
8
- INFO: 2025-12-02T07:32:04 - app.main: ============================================================
9
- INFO: 2025-12-02T07:32:04 - app.main: 📦 Database:
10
- INFO: 2025-12-02T07:32:04 - app.main: ✓ Connected | 45 tables | 6 users
11
- INFO: 2025-12-02T07:32:04 - app.main: 💾 Cache & Sessions:
12
- INFO: 2025-12-02T07:32:05 - app.services.otp_service: ✅ OTP Service initialized with Redis storage
13
- INFO: 2025-12-02T07:32:06 - app.main: ✓ Redis: Connected
14
- INFO: 2025-12-02T07:32:06 - app.main: 🔌 External Services:
15
- INFO: 2025-12-02T07:32:06 - app.main: ✓ Cloudinary: Connected
16
- INFO: 2025-12-02T07:32:06 - app.main: ✓ Resend: Configured
17
- INFO: 2025-12-02T07:32:06 - app.main: ○ WASender: Failed
18
- INFO: 2025-12-02T07:32:06 - app.main: ✓ Supabase: Connected | 6 buckets
19
- INFO: 2025-12-02T07:32:06 - app.main: ============================================================
20
- INFO: 2025-12-02T07:32:06 - app.main: ✅ Startup complete | Ready to serve requests
21
- INFO: 2025-12-02T07:32:06 - app.main: ============================================================
22
  INFO: Application startup complete.
23
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
24
- INFO: 10.16.34.155:35646 - "GET /health HTTP/1.1" 200 OK
25
- INFO: 2025-12-02T07:32:11 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
26
- INFO: 2025-12-02T07:32:11 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
27
- INFO: 10.16.30.4:48107 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
28
- INFO: 2025-12-02T07:32:11 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
29
- INFO: 2025-12-02T07:32:11 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
30
- INFO: 10.16.30.4:48107 - "GET /api/v1/profile/me HTTP/1.1" 200 OK
31
- INFO: 2025-12-02T07:32:11 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
32
- INFO: 2025-12-02T07:32:11 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
33
- INFO: 10.16.34.155:35646 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
34
- INFO: 2025-12-02T07:32:11 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
35
- INFO: 2025-12-02T07:32:11 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
36
- INFO: 10.16.30.4:55605 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
37
- INFO: 2025-12-02T07:32:12 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
38
- INFO: 2025-12-02T07:32:12 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
39
- INFO: 10.16.34.155:35646 - "GET /api/v1/financial-accounts/me HTTP/1.1" 200 OK
40
- INFO: 2025-12-02T07:32:12 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
41
- INFO: 2025-12-02T07:32:12 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
42
- INFO: 10.16.30.4:55605 - "GET /api/v1/asset-assignments/me HTTP/1.1" 200 OK
43
- INFO: 10.16.34.155:53752 - "GET /health HTTP/1.1" 200 OK
44
- INFO: 10.16.30.4:8310 - "GET /health HTTP/1.1" 200 OK
45
- INFO: 2025-12-02T07:33:38 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
46
- INFO: 2025-12-02T07:33:38 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
47
- INFO: 2025-12-02T07:33:38 - app.services.profile_service: Basic profile updated for user 43b778b0-2062-4724-abbb-916a4835a9b0 by 43b778b0-2062-4724-abbb-916a4835a9b0
48
- INFO: 2025-12-02T07:33:38 - app.services.audit_service: Audit log created: update on user by viyisa8151@feralrex.com
49
- INFO: 10.16.34.155:58980 - "PUT /api/v1/profile/me/basic HTTP/1.1" 200 OK
50
- INFO: 2025-12-02T07:33:38 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
51
- INFO: 2025-12-02T07:33:38 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
52
- INFO: 10.16.30.4:35028 - "GET /api/v1/profile/me HTTP/1.1" 200 OK
53
- INFO: 10.16.34.155:60509 - "GET /health HTTP/1.1" 200 OK
54
- INFO: 10.16.30.4:52588 - "GET /health HTTP/1.1" 200 OK
55
- INFO: 2025-12-02T07:35:02 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
56
- INFO: 2025-12-02T07:35:02 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
57
- INFO: 2025-12-02T07:35:02 - app.services.profile_service: Location updated for user 43b778b0-2062-4724-abbb-916a4835a9b0 by 43b778b0-2062-4724-abbb-916a4835a9b0
58
- INFO: 2025-12-02T07:35:02 - app.services.audit_service: Audit log created: update on user by viyisa8151@feralrex.com
59
- INFO: 10.16.34.155:3726 - "PUT /api/v1/profile/me/location HTTP/1.1" 200 OK
60
- INFO: 2025-12-02T07:35:03 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
61
- INFO: 2025-12-02T07:35:03 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
62
- INFO: 10.16.34.155:3726 - "GET /api/v1/profile/me HTTP/1.1" 200 OK
63
- INFO: 10.16.30.4:3019 - "GET /health HTTP/1.1" 200 OK
64
- INFO: 10.16.30.4:27676 - "GET /health HTTP/1.1" 200 OK
65
- INFO: 10.16.30.4:30798 - "GET /health HTTP/1.1" 200 OK
66
- INFO: 10.16.30.4:20054 - "GET /health HTTP/1.1" 200 OK
67
- INFO: 10.16.34.155:37762 - "GET /health HTTP/1.1" 200 OK
68
- INFO: 10.16.30.4:55306 - "GET /health HTTP/1.1" 200 OK
69
- INFO: 10.16.30.4:23931 - "GET /health HTTP/1.1" 200 OK
70
- INFO: 10.16.30.4:53772 - "GET /health HTTP/1.1" 200 OK
71
- INFO: 10.16.30.4:16048 - "GET /health HTTP/1.1" 200 OK
72
- INFO: 10.16.30.4:55937 - "GET /health HTTP/1.1" 200 OK
73
- INFO: 2025-12-02T07:41:13 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
74
- INFO: 2025-12-02T07:41:13 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
75
- INFO: 2025-12-02T07:41:13 - app.services.profile_service: Health info updated for user 43b778b0-2062-4724-abbb-916a4835a9b0 by 43b778b0-2062-4724-abbb-916a4835a9b0
76
- INFO: 2025-12-02T07:41:13 - app.services.audit_service: Audit log created: update on user by viyisa8151@feralrex.com
77
- INFO: 10.16.34.155:11738 - "PUT /api/v1/profile/me/health HTTP/1.1" 200 OK
78
- INFO: 2025-12-02T07:41:13 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
79
- INFO: 2025-12-02T07:41:13 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
80
- INFO: 10.16.34.155:11738 - "GET /api/v1/profile/me HTTP/1.1" 200 OK
81
- INFO: 2025-12-02T07:41:55 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
82
- INFO: 2025-12-02T07:41:55 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
83
- INFO: 2025-12-02T07:41:55 - app.services.profile_service: PPE sizes updated for user 43b778b0-2062-4724-abbb-916a4835a9b0 by 43b778b0-2062-4724-abbb-916a4835a9b0
84
- INFO: 2025-12-02T07:41:55 - app.services.audit_service: Audit log created: update on user by viyisa8151@feralrex.com
85
- INFO: 10.16.30.4:55338 - "PUT /api/v1/profile/me/ppe HTTP/1.1" 200 OK
86
- INFO: 2025-12-02T07:41:56 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
87
- INFO: 2025-12-02T07:41:56 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
88
- INFO: 10.16.30.4:55338 - "GET /api/v1/profile/me HTTP/1.1" 200 OK
89
- INFO: 10.16.30.4:49827 - "GET /health HTTP/1.1" 200 OK
90
- INFO: 2025-12-02T07:42:42 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
91
- INFO: 2025-12-02T07:42:42 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
92
- INFO: 10.16.34.155:7533 - "POST /api/v1/financial-accounts/me HTTP/1.1" 422 Unprocessable Entity
93
- INFO: 2025-12-02T07:42:43 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
94
- INFO: 2025-12-02T07:42:43 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
95
- INFO: 10.16.34.155:7533 - "POST /api/v1/financial-accounts/me HTTP/1.1" 422 Unprocessable Entity
 
1
+ ===== Application Startup at 2025-12-02 08:37:34 =====
2
 
3
  INFO: Started server process [7]
4
  INFO: Waiting for application startup.
5
+ INFO: 2025-12-02T08:37:48 - app.main: ============================================================
6
+ INFO: 2025-12-02T08:37:48 - app.main: 🚀 SwiftOps API v1.0.0 | PRODUCTION
7
+ INFO: 2025-12-02T08:37:48 - app.main: 📊 Dashboard: Enabled
8
+ INFO: 2025-12-02T08:37:48 - app.main: ============================================================
9
+ INFO: 2025-12-02T08:37:48 - app.main: 📦 Database:
10
+ INFO: 2025-12-02T08:37:48 - app.main: ✓ Connected | 45 tables | 6 users
11
+ INFO: 2025-12-02T08:37:48 - app.main: 💾 Cache & Sessions:
12
+ INFO: 2025-12-02T08:37:49 - app.services.otp_service: ✅ OTP Service initialized with Redis storage
13
+ INFO: 2025-12-02T08:37:50 - app.main: ✓ Redis: Connected
14
+ INFO: 2025-12-02T08:37:50 - app.main: 🔌 External Services:
15
+ INFO: 2025-12-02T08:37:50 - app.main: ✓ Cloudinary: Connected
16
+ INFO: 2025-12-02T08:37:50 - app.main: ✓ Resend: Configured
17
+ INFO: 2025-12-02T08:37:50 - app.main: ○ WASender: Failed
18
+ INFO: 2025-12-02T08:37:50 - app.main: ✓ Supabase: Connected | 6 buckets
19
+ INFO: 2025-12-02T08:37:50 - app.main: ============================================================
20
+ INFO: 2025-12-02T08:37:50 - app.main: ✅ Startup complete | Ready to serve requests
21
+ INFO: 2025-12-02T08:37:50 - app.main: ============================================================
22
  INFO: Application startup complete.
23
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
24
+ INFO: 10.16.34.155:34732 - "GET /health HTTP/1.1" 200 OK
25
+ INFO: 2025-12-02T08:37:52 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
26
+ INFO: 2025-12-02T08:37:52 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
27
+ INFO: 10.16.30.4:22471 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
28
+ INFO: 2025-12-02T08:37:53 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
29
+ INFO: 2025-12-02T08:37:53 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
30
+ INFO: 10.16.34.155:34732 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
31
+ INFO: 2025-12-02T08:37:53 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
32
+ INFO: 2025-12-02T08:37:53 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
33
+ INFO: 10.16.34.155:54768 - "GET /api/v1/profile/me HTTP/1.1" 200 OK
34
+ INFO: 2025-12-02T08:37:53 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
35
+ INFO: 2025-12-02T08:37:53 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
36
+ INFO: 10.16.34.155:59168 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
37
+ INFO: 2025-12-02T08:37:54 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
38
+ INFO: 2025-12-02T08:37:54 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
39
+ INFO: 10.16.34.155:59168 - "GET /api/v1/financial-accounts/me HTTP/1.1" 200 OK
40
+ INFO: 2025-12-02T08:37:54 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
41
+ INFO: 2025-12-02T08:37:54 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
42
+ INFO: 10.16.34.155:54768 - "GET /api/v1/asset-assignments/me HTTP/1.1" 200 OK
43
+ INFO: 10.16.30.4:53781 - "GET /health HTTP/1.1" 200 OK
44
+ INFO: 2025-12-02T08:38:02 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
45
+ INFO: 2025-12-02T08:38:02 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
46
+ INFO: 10.16.30.4:53781 - "GET /api/v1/documents/users/me HTTP/1.1" 422 Unprocessable Entity
47
+ INFO: 2025-12-02T08:38:03 - app.api.deps: Checking active user: 43b778b0-2062-4724-abbb-916a4835a9b0, is_active: True, type: <class 'bool'>
48
+ INFO: 2025-12-02T08:38:03 - app.api.deps: User 43b778b0-2062-4724-abbb-916a4835a9b0 is active - proceeding
49
+ INFO: 10.16.30.4:53781 - "GET /api/v1/documents/users/me HTTP/1.1" 422 Unprocessable Entity
50
+ INFO: 10.16.34.155:16824 - "GET /health HTTP/1.1" 200 OK
51
+ INFO: 10.16.34.155:36219 - "GET /health HTTP/1.1" 200 OK
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app/api/v1/documents.py CHANGED
@@ -342,6 +342,52 @@ async def delete_document(
342
  # CONVENIENCE ENDPOINTS (Shortcuts)
343
  # ============================================
344
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  @router.post("/users/{user_id}/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
346
  async def upload_user_document(
347
  user_id: UUID,
@@ -388,6 +434,57 @@ async def get_user_documents(
388
  )
389
 
390
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
391
  @router.get("/users/{user_id}/profile-photo", response_model=Optional[DocumentResponse])
392
  async def get_user_profile_photo(
393
  user_id: UUID,
@@ -419,6 +516,14 @@ async def get_user_profile_photo(
419
 
420
  response = DocumentResponse.from_orm(document)
421
 
 
 
 
 
 
 
 
 
422
  # Add uploader info
423
  if document.uploaded_by_user_id:
424
  uploader = db.query(User).filter(User.id == document.uploaded_by_user_id).first()
@@ -535,6 +640,89 @@ async def get_latest_document(
535
  # PROFILE PHOTO SHORTCUTS
536
  # ============================================
537
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
  @router.post("/users/{user_id}/profile-photo", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
539
  async def upload_profile_photo(
540
  user_id: UUID,
@@ -544,7 +732,7 @@ async def upload_profile_photo(
544
  db: Session = Depends(get_db)
545
  ):
546
  """
547
- Upload or update user profile photo
548
 
549
  Automatically creates new version and marks old photo as outdated.
550
  Profile photos are stored in Cloudinary for optimization.
@@ -619,6 +807,23 @@ async def upload_profile_photo(
619
  return response
620
 
621
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622
  @router.get("/users/{user_id}/profile-photo/versions", response_model=List[DocumentResponse])
623
  async def get_profile_photo_versions(
624
  user_id: UUID,
 
342
  # CONVENIENCE ENDPOINTS (Shortcuts)
343
  # ============================================
344
 
345
+ # Current user endpoints (must come before parameterized routes)
346
+ @router.get("/users/me", response_model=DocumentListResponse)
347
+ async def get_my_documents(
348
+ document_type: Optional[str] = None,
349
+ current_user: User = Depends(get_current_active_user),
350
+ db: Session = Depends(get_db)
351
+ ):
352
+ """Get current user's documents"""
353
+ return await get_entity_documents(
354
+ entity_type="user",
355
+ entity_id=current_user.id,
356
+ document_type=document_type,
357
+ current_user=current_user,
358
+ db=db
359
+ )
360
+
361
+
362
+ @router.post("/users/me/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
363
+ async def upload_my_document(
364
+ file: UploadFile = File(...),
365
+ document_type: str = Form(...),
366
+ document_category: Optional[str] = Form(None),
367
+ description: Optional[str] = Form(None),
368
+ tags: Optional[str] = Form("[]"),
369
+ is_public: bool = Form(False),
370
+ request: Request = None,
371
+ current_user: User = Depends(get_current_active_user),
372
+ db: Session = Depends(get_db)
373
+ ):
374
+ """Upload document for current user"""
375
+ return await upload_document(
376
+ file=file,
377
+ entity_type="user",
378
+ entity_id=str(current_user.id),
379
+ document_type=document_type,
380
+ document_category=document_category,
381
+ description=description,
382
+ tags=tags,
383
+ is_public=is_public,
384
+ request=request,
385
+ current_user=current_user,
386
+ db=db
387
+ )
388
+
389
+
390
+ # Parameterized user endpoints (must come after /me routes)
391
  @router.post("/users/{user_id}/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
392
  async def upload_user_document(
393
  user_id: UUID,
 
434
  )
435
 
436
 
437
+ @router.get("/users/me/profile-photo", response_model=Optional[DocumentResponse])
438
+ async def get_my_profile_photo(
439
+ current_user: User = Depends(get_current_active_user),
440
+ db: Session = Depends(get_db)
441
+ ):
442
+ """
443
+ Get current user's profile photo (convenience endpoint)
444
+
445
+ Uses user_document_links for fast lookup
446
+ """
447
+ # Get profile photo link
448
+ doc_link = db.query(UserDocumentLink).filter(
449
+ UserDocumentLink.user_id == current_user.id,
450
+ UserDocumentLink.document_link_type == 'profile_photo'
451
+ ).first()
452
+
453
+ if not doc_link:
454
+ return None
455
+
456
+ # Get document
457
+ document = db.query(Document).filter(
458
+ Document.id == doc_link.document_id,
459
+ Document.deleted_at == None
460
+ ).first()
461
+
462
+ if not document:
463
+ return None
464
+
465
+ response = DocumentResponse.from_orm(document)
466
+
467
+ # Generate fresh signed URL for Supabase files
468
+ if document.storage_provider == 'supabase' and document.file_url.startswith('supabase://'):
469
+ from app.integrations.supabase import SupabaseStorageService
470
+ bucket = document.additional_metadata.get('bucket')
471
+ path = document.additional_metadata.get('path')
472
+ if bucket and path:
473
+ response.file_url = SupabaseStorageService.get_signed_url(bucket, path, 3600)
474
+
475
+ # Add uploader info
476
+ if document.uploaded_by_user_id:
477
+ uploader = db.query(User).filter(User.id == document.uploaded_by_user_id).first()
478
+ if uploader:
479
+ response.uploader = UploaderInfo(
480
+ id=uploader.id,
481
+ name=uploader.name,
482
+ email=uploader.email
483
+ )
484
+
485
+ return response
486
+
487
+
488
  @router.get("/users/{user_id}/profile-photo", response_model=Optional[DocumentResponse])
489
  async def get_user_profile_photo(
490
  user_id: UUID,
 
516
 
517
  response = DocumentResponse.from_orm(document)
518
 
519
+ # Generate fresh signed URL for Supabase files
520
+ if document.storage_provider == 'supabase' and document.file_url.startswith('supabase://'):
521
+ from app.integrations.supabase import SupabaseStorageService
522
+ bucket = document.additional_metadata.get('bucket')
523
+ path = document.additional_metadata.get('path')
524
+ if bucket and path:
525
+ response.file_url = SupabaseStorageService.get_signed_url(bucket, path, 3600)
526
+
527
  # Add uploader info
528
  if document.uploaded_by_user_id:
529
  uploader = db.query(User).filter(User.id == document.uploaded_by_user_id).first()
 
640
  # PROFILE PHOTO SHORTCUTS
641
  # ============================================
642
 
643
+ @router.post("/users/me/profile-photo", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
644
+ async def upload_my_profile_photo(
645
+ file: UploadFile = File(...),
646
+ request: Request = None,
647
+ current_user: User = Depends(get_current_active_user),
648
+ db: Session = Depends(get_db)
649
+ ):
650
+ """
651
+ Upload or update current user's profile photo
652
+
653
+ Automatically creates new version and marks old photo as outdated.
654
+ Profile photos are stored in Cloudinary for optimization.
655
+ """
656
+ # Validate file is an image
657
+ if not file.content_type.startswith('image/'):
658
+ raise HTTPException(
659
+ status_code=status.HTTP_400_BAD_REQUEST,
660
+ detail="Profile photo must be an image"
661
+ )
662
+
663
+ # Upload with versioning enabled (force Cloudinary for profile photos)
664
+ document = await StorageService.upload_file(
665
+ file=file,
666
+ entity_type="user",
667
+ entity_id=current_user.id,
668
+ document_type="profile_photo",
669
+ document_category="profile",
670
+ description="User profile photo",
671
+ tags=["profile", "photo"],
672
+ is_public=True,
673
+ uploaded_by_user_id=current_user.id,
674
+ db=db,
675
+ force_provider="cloudinary", # Force Cloudinary for profile photos
676
+ enable_versioning=True
677
+ )
678
+
679
+ # Update user_document_link
680
+ from app.models.user_document_link import UserDocumentLink
681
+ existing_link = db.query(UserDocumentLink).filter(
682
+ UserDocumentLink.user_id == current_user.id,
683
+ UserDocumentLink.document_link_type == 'profile_photo'
684
+ ).first()
685
+
686
+ if existing_link:
687
+ existing_link.document_id = document.id
688
+ existing_link.updated_at = datetime.utcnow().isoformat()
689
+ else:
690
+ doc_link = UserDocumentLink(
691
+ user_id=current_user.id,
692
+ document_id=document.id,
693
+ document_link_type='profile_photo',
694
+ notes="Profile photo"
695
+ )
696
+ db.add(doc_link)
697
+
698
+ db.commit()
699
+
700
+ # Audit log
701
+ AuditService.log_action(
702
+ db=db,
703
+ action='upload',
704
+ entity_type='document',
705
+ entity_id=str(document.id),
706
+ description=f"Profile photo uploaded for user {current_user.id}",
707
+ user=current_user,
708
+ request=request,
709
+ additional_metadata={
710
+ 'document_type': 'profile_photo',
711
+ 'version': document.version
712
+ }
713
+ )
714
+
715
+ # Get uploader info
716
+ response = DocumentResponse.from_orm(document)
717
+ response.uploader = UploaderInfo(
718
+ id=current_user.id,
719
+ name=current_user.name,
720
+ email=current_user.email
721
+ )
722
+
723
+ return response
724
+
725
+
726
  @router.post("/users/{user_id}/profile-photo", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
727
  async def upload_profile_photo(
728
  user_id: UUID,
 
732
  db: Session = Depends(get_db)
733
  ):
734
  """
735
+ Upload or update user profile photo (admin/manager)
736
 
737
  Automatically creates new version and marks old photo as outdated.
738
  Profile photos are stored in Cloudinary for optimization.
 
807
  return response
808
 
809
 
810
+ @router.get("/users/me/profile-photo/versions", response_model=List[DocumentResponse])
811
+ async def get_my_profile_photo_versions(
812
+ current_user: User = Depends(get_current_active_user),
813
+ db: Session = Depends(get_db)
814
+ ):
815
+ """
816
+ Get all versions of current user's profile photo
817
+ """
818
+ return await get_document_versions(
819
+ entity_type="user",
820
+ entity_id=current_user.id,
821
+ document_type="profile_photo",
822
+ current_user=current_user,
823
+ db=db
824
+ )
825
+
826
+
827
  @router.get("/users/{user_id}/profile-photo/versions", response_model=List[DocumentResponse])
828
  async def get_profile_photo_versions(
829
  user_id: UUID,