kamau1 commited on
Commit
337e2ae
·
1 Parent(s): 717d701

Fix contractor invoice list route by removing trailing slash to prevent 307 redirects and CORS failures

Browse files
docs/api/invoicing/FRONTEND_FIX_REQUIRED.md ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Frontend Fix Required - Invoice API Endpoints
2
+
3
+ ## Issues Fixed
4
+
5
+ ### 1. Wrong Endpoint Paths (404 errors)
6
+ Frontend was calling `/api/v1/invoices/*` instead of `/api/v1/contractor-invoices/*`
7
+
8
+ ### 2. Trailing Slash Redirect (307 + CORS errors)
9
+ Backend was redirecting `/contractor-invoices` → `/contractor-invoices/` causing CORS preflight failures.
10
+ **FIXED:** Changed route definitions from `@router.get("/")` to `@router.get("")`
11
+
12
+ ## Current (Wrong) Frontend Calls
13
+ ```javascript
14
+ // ❌ WRONG - These return 404
15
+ GET /api/v1/invoices/stats?project_id=...
16
+ GET /api/v1/invoices?project_id=...
17
+ ```
18
+
19
+ ## Correct Endpoints to Use
20
+
21
+ ### For Invoice Stats and Listing
22
+ ```javascript
23
+ // ✅ CORRECT
24
+ GET /api/v1/contractor-invoices/stats?project_id=...
25
+ GET /api/v1/contractor-invoices?project_id=...
26
+ GET /api/v1/contractor-invoices/{id}
27
+ ```
28
+
29
+ ### For Invoice Generation (these are correct)
30
+ ```javascript
31
+ // ✅ Already correct
32
+ POST /api/v1/invoices/generate
33
+ GET /api/v1/invoices/available-tickets
34
+ GET /api/v1/invoices/{id}/export/csv
35
+ GET /api/v1/invoices/view?token=...
36
+ ```
37
+
38
+ ## Files to Update
39
+
40
+ ### 1. `invoice.service.ts`
41
+ ```typescript
42
+ // Change this:
43
+ getStats: (params) => api.get('/invoices/stats', { params })
44
+ getInvoices: (params) => api.get('/invoices', { params })
45
+
46
+ // To this:
47
+ getStats: (params) => api.get('/contractor-invoices/stats', { params })
48
+ getInvoices: (params) => api.get('/contractor-invoices', { params })
49
+ ```
50
+
51
+ ### 2. Any other files calling `/api/v1/invoices/stats` or `/api/v1/invoices?`
52
+
53
+ ## Complete Endpoint Map
54
+
55
+ | Purpose | Endpoint | Notes |
56
+ |---------|----------|-------|
57
+ | **Dashboard stats** | `GET /contractor-invoices/stats` | Changed from `/invoices/stats` |
58
+ | **List invoices** | `GET /contractor-invoices` | Changed from `/invoices` |
59
+ | **Invoice details** | `GET /contractor-invoices/{id}` | Changed from `/invoices/{id}` |
60
+ | **Update invoice** | `PUT /contractor-invoices/{id}` | Changed from `/invoices/{id}` |
61
+ | **Available tickets** | `GET /invoices/available-tickets` | ✅ Correct |
62
+ | **Generate invoice** | `POST /invoices/generate` | ✅ Correct |
63
+ | **Export CSV** | `GET /invoices/{id}/export/csv` | ✅ Correct |
64
+ | **Public view** | `GET /invoices/view?token=...` | ✅ Correct |
65
+
66
+ ## Why Two Different Prefixes?
67
+
68
+ - `/contractor-invoices/*` - CRUD operations on existing invoices (view, update, delete)
69
+ - `/invoices/*` - Invoice generation workflow (create from tickets, export, public viewing)
70
+
71
+ This separation keeps the generation workflow clean and separate from invoice management.
72
+
73
+ ## Testing After Fix
74
+
75
+ After updating the frontend, you should see:
76
+ ```
77
+ ✅ GET /api/v1/contractor-invoices/stats → 200 OK
78
+ ✅ GET /api/v1/contractor-invoices?project_id=... → 200 OK
79
+ ```
80
+
81
+ Instead of:
82
+ ```
83
+ ❌ GET /api/v1/invoices/stats → 404 Not Found
84
+ ❌ GET /api/v1/invoices?project_id=... → 404 Not Found
85
+ ```
docs/devlogs/browser/browserconsole.txt CHANGED
@@ -32,86 +32,14 @@ flushPassiveEffects @ chunk-276SZO74.js?v=bb94d704:19447
32
  workLoop @ chunk-276SZO74.js?v=bb94d704:197
33
  flushWork @ chunk-276SZO74.js?v=bb94d704:176
34
  performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
35
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (888ms)
36
  core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences
37
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/tickets/1f807cf8-f139-421b-86e3-38c2f8bc7070/detail
38
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences → 200 (430ms)
39
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/tickets/1f807cf8-f139-421b-86e3-38c2f8bc7070/detail → 200 (1.71s)
40
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me
41
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me 200 (999ms)
42
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/tickets/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&status=open%2Cpending_review
43
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/tickets?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=50&status=open%2Cpending_review
44
- core.ts:119 ℹ️ [19:25:12] [COMPONENT] TicketsDashboard: Tickets dashboard loaded {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a'}
45
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/regions
46
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/regions → 200 (407ms)
47
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/tickets/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&status=open%2Cpending_review → 200 (474ms)
48
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/tickets?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=50&status=open%2Cpending_review → 200 (682ms)
49
- core.ts:119 ℹ️ [19:25:15] [COMPONENT] AppLauncher: App clicked {appCode: 'invoicing', route: '/invoicing', primaryProject: '0ade6bd1-e492-4e25-b681-59f42058d29a', currentPath: '/project/0ade6bd1-e492-4e25-b681-59f42058d29a/tickets', metaApps: Array(6)}
50
- core.ts:119 ℹ️ [19:25:15] [COMPONENT] AppLauncher: Navigation decision {hasProject: true, isInProjectContext: true, isMetaApp: false, appCode: 'invoicing', metaApps: Array(6)}
51
- core.ts:119 ℹ️ [19:25:15] [COMPONENT] AppLauncher: Navigating to global route {route: '/invoicing', appCode: 'invoicing'}
52
- NotFound.tsx:8 404 Error: User attempted to access non-existent route: /invoicing
53
- (anonymous) @ NotFound.tsx:8
54
- commitHookEffectListMount @ chunk-276SZO74.js?v=bb94d704:16915
55
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=bb94d704:18156
56
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=bb94d704:18129
57
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=bb94d704:18119
58
- commitPassiveMountEffects @ chunk-276SZO74.js?v=bb94d704:18109
59
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=bb94d704:19490
60
- flushPassiveEffects @ chunk-276SZO74.js?v=bb94d704:19447
61
- (anonymous) @ chunk-276SZO74.js?v=bb94d704:19328
62
- workLoop @ chunk-276SZO74.js?v=bb94d704:197
63
- flushWork @ chunk-276SZO74.js?v=bb94d704:176
64
- performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
65
- core.ts:119 ℹ️ [19:28:57] [COMPONENT] TicketsDashboard: Tickets dashboard loaded {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a'}
66
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/regions
67
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/regions → 200 (1.32s)
68
- core.ts:119 ℹ️ [19:29:05] [COMPONENT] AppLauncher: App clicked {appCode: 'invoicing', route: '/invoicing', primaryProject: '0ade6bd1-e492-4e25-b681-59f42058d29a', currentPath: '/project/0ade6bd1-e492-4e25-b681-59f42058d29a/tickets', metaApps: Array(6)}
69
- core.ts:119 ℹ️ [19:29:05] [COMPONENT] AppLauncher: Navigation decision {hasProject: true, isInProjectContext: true, isMetaApp: false, appCode: 'invoicing', metaApps: Array(6)}
70
- core.ts:119 ℹ️ [19:29:05] [COMPONENT] AppLauncher: Navigating to project-scoped route {projectRoute: '/project/0ade6bd1-e492-4e25-b681-59f42058d29a/invoicing', appCode: 'invoicing'}
71
- NotFound.tsx:8 404 Error: User attempted to access non-existent route: /project/0ade6bd1-e492-4e25-b681-59f42058d29a/invoicing
72
- (anonymous) @ NotFound.tsx:8
73
- commitHookEffectListMount @ chunk-276SZO74.js?v=bb94d704:16915
74
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=bb94d704:18156
75
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=bb94d704:18129
76
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=bb94d704:18119
77
- commitPassiveMountEffects @ chunk-276SZO74.js?v=bb94d704:18109
78
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=bb94d704:19490
79
- flushPassiveEffects @ chunk-276SZO74.js?v=bb94d704:19447
80
- commitRootImpl @ chunk-276SZO74.js?v=bb94d704:19416
81
- commitRoot @ chunk-276SZO74.js?v=bb94d704:19277
82
- performSyncWorkOnRoot @ chunk-276SZO74.js?v=bb94d704:18895
83
- flushSyncCallbacks @ chunk-276SZO74.js?v=bb94d704:9119
84
- (anonymous) @ chunk-276SZO74.js?v=bb94d704:18627
85
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me
86
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (1.14s)
87
- core.ts:119 ℹ️ [19:30:36] [COMPONENT] Dashboard component selected {role: 'project_manager', componentName: 'ProjectManagerDashboard', componentExists: true}
88
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/analytics/user/overview
89
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/analytics/user/overview → 200 (2.27s)
90
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/projects?page=1&per_page=100
91
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/projects?page=1&per_page=100 → 200 (820ms)
92
- core.ts:119 ℹ️ [19:30:49] [COMPONENT] Dashboard component selected {role: 'project_manager', componentName: 'ProjectManagerDashboard', componentExists: true}
93
- core.ts:119 ℹ️ [19:30:49] [COMPONENT] Dashboard component selected {role: 'project_manager', componentName: 'ProjectManagerDashboard', componentExists: true}
94
- core.ts:119 ℹ️ [19:31:07] [COMPONENT] Dashboard component selected {role: 'project_manager', componentName: 'ProjectManagerDashboard', componentExists: true}
95
- core.ts:119 ℹ️ [19:31:09] [COMPONENT] ProjectList: Project selected {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a', title: 'Atomio Fttx', status: 'active', willNavigateToSetup: false}
96
- core.ts:119 ℹ️ [19:31:09] [COMPONENT] ProjectList: Switching to project {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a'}
97
- core.ts:119 ℹ️ [19:31:09] [AUTH] Updating user preferences {last_active_project_id: '0ade6bd1-e492-4e25-b681-59f42058d29a'}
98
- core.ts:169 %cPUT%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences
99
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me
100
- core.ts:119 ℹ️ [19:31:10] [COMPONENT] ProjectDashboardPage: Project dashboard loaded {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a', currentProject: undefined}
101
- core.ts:169 PUT https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences → 200 (839ms)
102
- core.ts:119 ℹ️ [19:31:10] [AUTH] Preferences updated successfully {last_active_project_id: '0ade6bd1-e492-4e25-b681-59f42058d29a'}
103
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (509ms)
104
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/dashboard
105
- core.ts:119 ℹ️ [19:31:11] [COMPONENT] ProjectDashboardPage: Project dashboard loaded {projectId: '0ade6bd1-e492-4e25-b681-59f42058d29a', currentProject: 'Atomio Fttx'}
106
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/dashboard → 200 (540.71s)
107
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/tickets/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
108
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/tickets/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 200 (679ms)
109
- core.ts:119 ℹ️ [19:31:15] [COMPONENT] AppLauncher: App clicked {appCode: 'invoicing', route: '/invoicing', primaryProject: '0ade6bd1-e492-4e25-b681-59f42058d29a', currentPath: '/project/0ade6bd1-e492-4e25-b681-59f42058d29a', metaApps: Array(6)}
110
- core.ts:119 ℹ️ [19:31:15] [COMPONENT] AppLauncher: Navigation decision {hasProject: true, isInProjectContext: true, isMetaApp: false, appCode: 'invoicing', metaApps: Array(6)}
111
- core.ts:119 ℹ️ [19:31:15] [COMPONENT] AppLauncher: Navigating to project-scoped route {projectRoute: '/project/0ade6bd1-e492-4e25-b681-59f42058d29a/invoicing', appCode: 'invoicing'}
112
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
113
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
114
- api-client.ts:124 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a 404 (Not Found)
115
  request @ api-client.ts:124
116
  get @ api-client.ts:202
117
  getInvoices @ invoice.service.ts:25
@@ -136,36 +64,10 @@ flushPassiveEffects @ chunk-276SZO74.js?v=bb94d704:19447
136
  workLoop @ chunk-276SZO74.js?v=bb94d704:197
137
  flushWork @ chunk-276SZO74.js?v=bb94d704:176
138
  performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
139
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 404 (1.71s)
140
- api-client.ts:124 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a 404 (Not Found)
141
- request @ api-client.ts:124
142
- get @ api-client.ts:202
143
- getStats @ invoice.service.ts:13
144
- queryFn @ useInvoices.ts:8
145
- fetchFn @ @tanstack_react-query.js?v=bb94d704:881
146
- run @ @tanstack_react-query.js?v=bb94d704:513
147
- start @ @tanstack_react-query.js?v=bb94d704:555
148
- fetch @ @tanstack_react-query.js?v=bb94d704:969
149
- executeFetch_fn @ @tanstack_react-query.js?v=bb94d704:2280
150
- onSubscribe @ @tanstack_react-query.js?v=bb94d704:1983
151
- subscribe @ @tanstack_react-query.js?v=bb94d704:24
152
- (anonymous) @ @tanstack_react-query.js?v=bb94d704:3147
153
- subscribeToStore @ chunk-276SZO74.js?v=bb94d704:11984
154
- commitHookEffectListMount @ chunk-276SZO74.js?v=bb94d704:16915
155
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=bb94d704:18156
156
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=bb94d704:18129
157
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=bb94d704:18119
158
- commitPassiveMountEffects @ chunk-276SZO74.js?v=bb94d704:18109
159
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=bb94d704:19490
160
- flushPassiveEffects @ chunk-276SZO74.js?v=bb94d704:19447
161
- (anonymous) @ chunk-276SZO74.js?v=bb94d704:19328
162
- workLoop @ chunk-276SZO74.js?v=bb94d704:197
163
- flushWork @ chunk-276SZO74.js?v=bb94d704:176
164
- performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
165
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 404 (1.74s)
166
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
167
- core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
168
- api-client.ts:124 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a 404 (Not Found)
169
  request @ api-client.ts:124
170
  get @ api-client.ts:202
171
  getInvoices @ invoice.service.ts:25
@@ -195,35 +97,4 @@ flushPassiveEffects @ chunk-276SZO74.js?v=bb94d704:19447
195
  workLoop @ chunk-276SZO74.js?v=bb94d704:197
196
  flushWork @ chunk-276SZO74.js?v=bb94d704:176
197
  performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
198
- api-client.ts:124 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a 404 (Not Found)
199
- request @ api-client.ts:124
200
- get @ api-client.ts:202
201
- getStats @ invoice.service.ts:13
202
- queryFn @ useInvoices.ts:8
203
- fetchFn @ @tanstack_react-query.js?v=bb94d704:881
204
- run @ @tanstack_react-query.js?v=bb94d704:513
205
- (anonymous) @ @tanstack_react-query.js?v=bb94d704:538
206
- Promise.then
207
- (anonymous) @ @tanstack_react-query.js?v=bb94d704:534
208
- Promise.catch
209
- run @ @tanstack_react-query.js?v=bb94d704:517
210
- start @ @tanstack_react-query.js?v=bb94d704:555
211
- fetch @ @tanstack_react-query.js?v=bb94d704:969
212
- executeFetch_fn @ @tanstack_react-query.js?v=bb94d704:2280
213
- onSubscribe @ @tanstack_react-query.js?v=bb94d704:1983
214
- subscribe @ @tanstack_react-query.js?v=bb94d704:24
215
- (anonymous) @ @tanstack_react-query.js?v=bb94d704:3147
216
- subscribeToStore @ chunk-276SZO74.js?v=bb94d704:11984
217
- commitHookEffectListMount @ chunk-276SZO74.js?v=bb94d704:16915
218
- commitPassiveMountOnFiber @ chunk-276SZO74.js?v=bb94d704:18156
219
- commitPassiveMountEffects_complete @ chunk-276SZO74.js?v=bb94d704:18129
220
- commitPassiveMountEffects_begin @ chunk-276SZO74.js?v=bb94d704:18119
221
- commitPassiveMountEffects @ chunk-276SZO74.js?v=bb94d704:18109
222
- flushPassiveEffectsImpl @ chunk-276SZO74.js?v=bb94d704:19490
223
- flushPassiveEffects @ chunk-276SZO74.js?v=bb94d704:19447
224
- (anonymous) @ chunk-276SZO74.js?v=bb94d704:19328
225
- workLoop @ chunk-276SZO74.js?v=bb94d704:197
226
- flushWork @ chunk-276SZO74.js?v=bb94d704:176
227
- performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
228
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 404 (287ms)
229
- core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 404 (283ms)
 
32
  workLoop @ chunk-276SZO74.js?v=bb94d704:197
33
  flushWork @ chunk-276SZO74.js?v=bb94d704:176
34
  performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
35
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me → 200 (430ms)
36
  core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences
37
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/auth/me/preferences → 200 (651ms)
38
+ core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
39
+ core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
40
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 200 (424ms)
41
+ invoicing:1 Access to fetch at 'http://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a' (redirected from 'https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
42
+ api-client.ts:124 GET http://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a net::ERR_FAILED
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  request @ api-client.ts:124
44
  get @ api-client.ts:202
45
  getInvoices @ invoice.service.ts:25
 
64
  workLoop @ chunk-276SZO74.js?v=bb94d704:197
65
  flushWork @ chunk-276SZO74.js?v=bb94d704:176
66
  performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
67
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a → 0 (543ms)
68
+ core.ts:169 %cGET%c https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a
69
+ invoicing:1 Access to fetch at 'http://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a' (redirected from 'https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a') from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
70
+ api-client.ts:124 GET http://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices/?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a net::ERR_FAILED
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  request @ api-client.ts:124
72
  get @ api-client.ts:202
73
  getInvoices @ invoice.service.ts:25
 
97
  workLoop @ chunk-276SZO74.js?v=bb94d704:197
98
  flushWork @ chunk-276SZO74.js?v=bb94d704:176
99
  performWorkUntilDeadline @ chunk-276SZO74.js?v=bb94d704:384
100
+ core.ts:169 GET https://kamau1-swiftops-backend.hf.space/api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a 0 (1.24s)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/devlogs/server/runtimeerror.txt CHANGED
@@ -1,150 +1,69 @@
1
- ===== Application Startup at 2025-12-10 19:07:27 =====
2
 
3
  INFO: Started server process [7]
4
  INFO: Waiting for application startup.
5
- INFO: 2025-12-10T19:07:41 - app.main: ============================================================
6
- INFO: 2025-12-10T19:07:41 - app.main: 🚀 SwiftOps API v1.0.0 | PRODUCTION
7
- INFO: 2025-12-10T19:07:41 - app.main: 📊 Dashboard: Enabled
8
- INFO: 2025-12-10T19:07:41 - app.main: ============================================================
9
- INFO: 2025-12-10T19:07:41 - app.main: 📦 Database:
10
- INFO: 2025-12-10T19:07:41 - app.main: ✓ Connected | 47 tables | 6 users
11
- INFO: 2025-12-10T19:07:41 - app.main: 💾 Cache & Sessions:
12
- INFO: 2025-12-10T19:07:42 - app.services.otp_service: ✅ OTP Service initialized with Redis storage
13
- INFO: 2025-12-10T19:07:43 - app.main: ✓ Redis: Connected
14
- INFO: 2025-12-10T19:07:43 - app.main: 🔌 External Services:
15
- INFO: 2025-12-10T19:07:43 - app.main: ✓ Cloudinary: Connected
16
- INFO: 2025-12-10T19:07:43 - app.main: ✓ Resend: Configured
17
- INFO: 2025-12-10T19:07:43 - app.main: ○ WASender: Disconnected
18
- INFO: 2025-12-10T19:07:43 - app.main: ✓ Supabase: Connected | 6 buckets
19
- INFO: 2025-12-10T19:07:43 - app.main: ⏰ Scheduler:
20
- INFO: 2025-12-10T19:07:43 - apscheduler.scheduler: Adding job tentatively -- it will be properly scheduled when the scheduler starts
21
- INFO: 2025-12-10T19:07:43 - apscheduler.scheduler: Added job "Daily Field Agent Reconciliation" to job store "default"
22
- INFO: 2025-12-10T19:07:43 - apscheduler.scheduler: Scheduler started
23
- INFO: 2025-12-10T19:07:43 - app.tasks.scheduler: Reconciliation scheduler started (runs at 10 PM Africa/Nairobi)
24
- INFO: 2025-12-10T19:07:43 - app.main: ✓ Daily reconciliation scheduler started (runs at midnight)
25
- INFO: 2025-12-10T19:07:43 - app.main: ============================================================
26
- INFO: 2025-12-10T19:07:43 - app.main: ✅ Startup complete | Ready to serve requests
27
- INFO: 2025-12-10T19:07:43 - app.main: ============================================================
28
  INFO: Application startup complete.
29
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
30
- INFO: 10.16.37.13:20556 - "GET /health HTTP/1.1" 200 OK
31
- INFO: 10.16.37.13:15485 - "GET /health HTTP/1.1" 200 OK
32
- INFO: 2025-12-10T19:10:11 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
33
- INFO: 2025-12-10T19:10:11 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
34
- INFO: 10.16.37.13:15485 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
35
- INFO: 2025-12-10T19:10:12 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
36
- INFO: 2025-12-10T19:10:12 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
37
- INFO: 10.16.37.13:15485 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
38
- INFO: 2025-12-10T19:10:12 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
39
- INFO: 2025-12-10T19:10:12 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
40
- INFO: 10.16.13.79:10672 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
41
- INFO: 10.16.13.79:10672 - "GET /api/v1/ticket-expenses/stats/summary?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=20&status=pending HTTP/1.1" 200 OK
42
- INFO: 10.16.37.13:15485 - "GET /api/v1/ticket-expenses?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=20&is_approved=false HTTP/1.1" 200 OK
43
- INFO: 10.16.37.13:19577 - "GET /health HTTP/1.1" 200 OK
44
- INFO: 2025-12-10T19:10:32 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
45
- INFO: 2025-12-10T19:10:32 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
46
- INFO: 10.16.13.79:58151 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
47
- INFO: 2025-12-10T19:10:33 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
48
- INFO: 2025-12-10T19:10:33 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
49
- INFO: 10.16.13.79:58151 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
50
- INFO: 2025-12-10T19:10:33 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
51
- INFO: 2025-12-10T19:10:33 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
52
- INFO: 10.16.37.13:19577 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
53
- INFO: 10.16.37.13:19577 - "GET /api/v1/ticket-expenses/stats/summary?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=20&status=pending HTTP/1.1" 200 OK
54
- INFO: 10.16.37.13:47089 - "GET /api/v1/ticket-expenses?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=20&is_approved=false HTTP/1.1" 200 OK
55
- INFO: 10.16.37.13:56626 - "GET /health HTTP/1.1" 200 OK
56
- INFO: 10.16.37.13:49300 - "GET /health HTTP/1.1" 200 OK
57
- INFO: 2025-12-10T19:15:33 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
58
- INFO: 2025-12-10T19:15:33 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
59
- INFO: 10.16.37.13:49300 - "GET /api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/regions HTTP/1.1" 200 OK
60
- INFO: 10.16.13.79:61032 - "GET /api/v1/tickets/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&status=open%2Cpending_review HTTP/1.1" 200 OK
61
- INFO: 2025-12-10T19:15:33 - app.services.ticket_service: Listed 6 tickets (total: 6) for user c5cf92be-4172-4fe2-af5c-f05d83b3a938
62
- INFO: 10.16.13.79:40625 - "GET /api/v1/tickets?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=50&status=open%2Cpending_review HTTP/1.1" 200 OK
63
- INFO: 10.16.13.79:33596 - "GET /health HTTP/1.1" 200 OK
64
- INFO: 10.16.37.13:17382 - "GET / HTTP/1.1" 200 OK
65
- INFO: 10.16.13.79:21028 - "GET /api/v1/tickets/1f807cf8-f139-421b-86e3-38c2f8bc7070/detail HTTP/1.1" 200 OK
66
- INFO: 10.16.13.79:8092 - "GET /health HTTP/1.1" 200 OK
67
- INFO: 10.16.37.13:25204 - "GET /health HTTP/1.1" 200 OK
68
- INFO: 10.16.13.79:28441 - "GET /health HTTP/1.1" 200 OK
69
- INFO: 2025-12-10T19:20:57 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
70
- INFO: 2025-12-10T19:20:57 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
71
- INFO: 10.16.13.79:28441 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
72
- INFO: 2025-12-10T19:20:57 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
73
- INFO: 2025-12-10T19:20:57 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
74
- INFO: 10.16.37.13:9285 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
75
- INFO: 10.16.37.13:46655 - "GET /health HTTP/1.1" 200 OK
76
- INFO: 2025-12-10T19:21:40 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
77
- INFO: 2025-12-10T19:21:40 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
78
- INFO: 10.16.13.79:63227 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
79
- INFO: 2025-12-10T19:21:42 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
80
- INFO: 2025-12-10T19:21:42 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
81
- INFO: 10.16.13.79:63227 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
82
- INFO: 2025-12-10T19:21:42 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
83
- INFO: 2025-12-10T19:21:42 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
84
- INFO: 10.16.37.13:46655 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
85
- INFO: 10.16.13.79:63227 - "GET /api/v1/tickets/1f807cf8-f139-421b-86e3-38c2f8bc7070/detail HTTP/1.1" 200 OK
86
- INFO: 10.16.13.79:35805 - "GET /health HTTP/1.1" 200 OK
87
- INFO: 2025-12-10T19:22:11 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
88
- INFO: 2025-12-10T19:22:11 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
89
- INFO: 10.16.37.13:54443 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
90
- INFO: 2025-12-10T19:22:13 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
91
- INFO: 2025-12-10T19:22:13 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
92
- INFO: 10.16.13.79:35805 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
93
- INFO: 2025-12-10T19:22:13 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
94
- INFO: 2025-12-10T19:22:13 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
95
- INFO: 10.16.37.13:54443 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
96
- INFO: 10.16.13.79:35805 - "GET /api/v1/tickets/1f807cf8-f139-421b-86e3-38c2f8bc7070/detail HTTP/1.1" 200 OK
97
- INFO: 10.16.37.13:58621 - "GET /health HTTP/1.1" 200 OK
98
- INFO: 10.16.13.79:19517 - "GET /health HTTP/1.1" 200 OK
99
- INFO: 2025-12-10T19:25:11 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
100
- INFO: 2025-12-10T19:25:11 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
101
- INFO: 10.16.13.79:6287 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
102
- INFO: 2025-12-10T19:25:11 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
103
- INFO: 2025-12-10T19:25:11 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
104
- INFO: 10.16.37.13:22683 - "GET /api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/regions HTTP/1.1" 200 OK
105
- INFO: 10.16.37.13:15495 - "GET /api/v1/tickets/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&status=open%2Cpending_review HTTP/1.1" 200 OK
106
- INFO: 2025-12-10T19:25:12 - app.services.ticket_service: Listed 6 tickets (total: 6) for user c5cf92be-4172-4fe2-af5c-f05d83b3a938
107
- INFO: 10.16.13.79:6287 - "GET /api/v1/tickets?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page=1&page_size=50&status=open%2Cpending_review HTTP/1.1" 200 OK
108
- INFO: 10.16.13.79:16678 - "GET /health HTTP/1.1" 200 OK
109
- INFO: 10.16.37.13:5868 - "GET /health HTTP/1.1" 200 OK
110
- INFO: 10.16.37.13:14138 - "GET /health HTTP/1.1" 200 OK
111
- INFO: 2025-12-10T19:28:57 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
112
- INFO: 2025-12-10T19:28:57 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
113
- INFO: 10.16.13.79:13526 - "GET /api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/regions HTTP/1.1" 200 OK
114
- INFO: 10.16.37.13:49848 - "GET /health HTTP/1.1" 200 OK
115
- INFO: 10.16.13.79:14469 - "GET /health HTTP/1.1" 200 OK
116
- INFO: 10.16.13.79:40564 - "GET /health HTTP/1.1" 200 OK
117
- INFO: 2025-12-10T19:30:34 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
118
- INFO: 2025-12-10T19:30:34 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
119
- INFO: 10.16.37.13:28814 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
120
- INFO: 2025-12-10T19:30:36 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
121
- INFO: 2025-12-10T19:30:36 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
122
- INFO: 10.16.13.79:40564 - "GET /api/v1/analytics/user/overview HTTP/1.1" 200 OK
123
- INFO: 2025-12-10T19:30:38 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
124
- INFO: 2025-12-10T19:30:38 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
125
- INFO: 2025-12-10T19:30:38 - app.services.project_service: Listed 1 projects (total: 1) for user c5cf92be-4172-4fe2-af5c-f05d83b3a938
126
- INFO: 10.16.37.13:10561 - "GET /api/v1/projects?page=1&per_page=100 HTTP/1.1" 200 OK
127
- INFO: 10.16.13.79:44883 - "GET /health HTTP/1.1" 200 OK
128
- INFO: 2025-12-10T19:31:09 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
129
- INFO: 2025-12-10T19:31:09 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
130
- INFO: 2025-12-10T19:31:09 - app.services.audit_service: Audit log created: update on user_preferences by nadina73@nembors.com
131
- INFO: 2025-12-10T19:31:09 - app.api.v1.auth: Preferences updated for user: nadina73@nembors.com
132
- INFO: 10.16.37.13:2250 - "PUT /api/v1/auth/me/preferences HTTP/1.1" 200 OK
133
- INFO: 2025-12-10T19:31:09 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
134
- INFO: 2025-12-10T19:31:09 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
135
- INFO: 10.16.37.13:15551 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
136
- INFO: 2025-12-10T19:31:10 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
137
- INFO: 2025-12-10T19:31:10 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
138
- INFO: 2025-12-10T19:31:10 - app.services.dashboard_service: Dashboard cache MISS for project 0ade6bd1-e492-4e25-b681-59f42058d29a, user c5cf92be-4172-4fe2-af5c-f05d83b3a938 - building fresh data
139
- INFO: 2025-12-10T19:31:11 - app.services.dashboard_service: Built and cached dashboard for project 0ade6bd1-e492-4e25-b681-59f42058d29a
140
- INFO: 10.16.37.13:15551 - "GET /api/v1/projects/0ade6bd1-e492-4e25-b681-59f42058d29a/dashboard HTTP/1.1" 200 OK
141
- INFO: 10.16.13.79:36107 - "GET /api/v1/notifications?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a&page_size=50&is_read=false HTTP/1.1" 200 OK
142
- INFO: 10.16.13.79:6804 - "GET /api/v1/tickets/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 200 OK
143
- INFO: 10.16.37.13:15187 - "GET /health HTTP/1.1" 200 OK
144
- INFO: 10.16.37.13:15187 - "GET /api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
145
- INFO: 10.16.13.79:14796 - "GET /api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
146
- INFO: 10.16.13.79:14796 - "GET /api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
147
- INFO: 10.16.37.13:15187 - "GET /api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
148
- INFO: 10.16.37.13:15187 - "GET /health HTTP/1.1" 200 OK
149
- INFO: 10.16.37.13:54090 - "GET /health HTTP/1.1" 200 OK
150
- INFO: 10.16.37.13:59743 - "GET /health HTTP/1.1" 200 OK
 
1
+ ===== Application Startup at 2025-12-10 19:39:46 =====
2
 
3
  INFO: Started server process [7]
4
  INFO: Waiting for application startup.
5
+ INFO: 2025-12-10T19:40:16 - app.main: ============================================================
6
+ INFO: 2025-12-10T19:40:16 - app.main: 🚀 SwiftOps API v1.0.0 | PRODUCTION
7
+ INFO: 2025-12-10T19:40:16 - app.main: 📊 Dashboard: Enabled
8
+ INFO: 2025-12-10T19:40:16 - app.main: ============================================================
9
+ INFO: 2025-12-10T19:40:16 - app.main: 📦 Database:
10
+ INFO: 2025-12-10T19:40:16 - app.main: ✓ Connected | 47 tables | 6 users
11
+ INFO: 2025-12-10T19:40:16 - app.main: 💾 Cache & Sessions:
12
+ INFO: 2025-12-10T19:40:17 - app.services.otp_service: ✅ OTP Service initialized with Redis storage
13
+ INFO: 2025-12-10T19:40:17 - app.main: ✓ Redis: Connected
14
+ INFO: 2025-12-10T19:40:17 - app.main: 🔌 External Services:
15
+ INFO: 2025-12-10T19:40:18 - app.main: ✓ Cloudinary: Connected
16
+ INFO: 2025-12-10T19:40:18 - app.main: ✓ Resend: Configured
17
+ INFO: 2025-12-10T19:40:18 - app.main: ○ WASender: Disconnected
18
+ INFO: 2025-12-10T19:40:18 - app.main: ✓ Supabase: Connected | 6 buckets
19
+ INFO: 2025-12-10T19:40:18 - app.main: ⏰ Scheduler:
20
+ INFO: 2025-12-10T19:40:18 - apscheduler.scheduler: Adding job tentatively -- it will be properly scheduled when the scheduler starts
21
+ INFO: 2025-12-10T19:40:18 - apscheduler.scheduler: Added job "Daily Field Agent Reconciliation" to job store "default"
22
+ INFO: 2025-12-10T19:40:18 - apscheduler.scheduler: Scheduler started
23
+ INFO: 2025-12-10T19:40:18 - app.tasks.scheduler: Reconciliation scheduler started (runs at 10 PM Africa/Nairobi)
24
+ INFO: 2025-12-10T19:40:18 - app.main: ✓ Daily reconciliation scheduler started (runs at midnight)
25
+ INFO: 2025-12-10T19:40:18 - app.main: ============================================================
26
+ INFO: 2025-12-10T19:40:18 - app.main: ✅ Startup complete | Ready to serve requests
27
+ INFO: 2025-12-10T19:40:18 - app.main: ============================================================
28
  INFO: Application startup complete.
29
  INFO: Uvicorn running on http://0.0.0.0:7860 (Press CTRL+C to quit)
30
+ INFO: 10.16.37.13:65163 - "GET /health HTTP/1.1" 200 OK
31
+ INFO: 10.16.37.13:6128 - "GET /health HTTP/1.1" 200 OK
32
+ INFO: 2025-12-10T19:40:25 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
33
+ INFO: 2025-12-10T19:40:25 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
34
+ INFO: 10.16.13.79:44265 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
35
+ INFO: 2025-12-10T19:40:27 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
36
+ INFO: 2025-12-10T19:40:27 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
37
+ INFO: 10.16.13.79:44265 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
38
+ INFO: 2025-12-10T19:40:27 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
39
+ INFO: 2025-12-10T19:40:27 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
40
+ INFO: 10.16.37.13:63000 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
41
+ INFO: 10.16.37.13:63000 - "GET /api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
42
+ INFO: 10.16.13.79:44265 - "GET /api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
43
+ INFO: 10.16.13.79:44265 - "GET /api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
44
+ INFO: 10.16.37.13:63000 - "GET /api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
45
+ INFO: 10.16.13.79:45793 - "GET /health HTTP/1.1" 200 OK
46
+ INFO: 10.16.37.13:45155 - "GET /api/v1/invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
47
+ INFO: 10.16.13.79:23611 - "GET /api/v1/invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 404 Not Found
48
+ INFO: 10.16.37.13:60532 - "GET /health HTTP/1.1" 200 OK
49
+ INFO: 10.16.37.13:60532 - "GET /api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 307 Temporary Redirect
50
+ INFO: 10.16.13.79:31854 - "GET / HTTP/1.1" 200 OK
51
+ INFO: 10.16.13.79:25120 - "GET /api/v1/contractor-invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 200 OK
52
+ INFO: 10.16.37.13:60532 - "GET / HTTP/1.1" 200 OK
53
+ INFO: 2025-12-10T19:45:09 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
54
+ INFO: 2025-12-10T19:45:09 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
55
+ INFO: 10.16.37.13:60532 - "GET /api/v1/auth/me HTTP/1.1" 200 OK
56
+ INFO: 10.16.13.79:40145 - "GET /health HTTP/1.1" 200 OK
57
+ INFO: 2025-12-10T19:45:09 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
58
+ INFO: 2025-12-10T19:45:09 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
59
+ INFO: 10.16.13.79:40145 - "GET /api/v1/auth/me/preferences/available-apps HTTP/1.1" 200 OK
60
+ INFO: 2025-12-10T19:45:09 - app.api.deps: Checking active user: c5cf92be-4172-4fe2-af5c-f05d83b3a938, is_active: True, type: <class 'bool'>
61
+ INFO: 2025-12-10T19:45:09 - app.api.deps: User c5cf92be-4172-4fe2-af5c-f05d83b3a938 is active - proceeding
62
+ INFO: 10.16.37.13:60532 - "GET /api/v1/auth/me/preferences HTTP/1.1" 200 OK
63
+ INFO: 10.16.13.79:40145 - "GET /api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 307 Temporary Redirect
64
+ INFO: 10.16.37.13:60532 - "GET /api/v1/contractor-invoices/stats?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 200 OK
65
+ INFO: 10.16.37.13:60532 - "GET /api/v1/contractor-invoices?project_id=0ade6bd1-e492-4e25-b681-59f42058d29a HTTP/1.1" 307 Temporary Redirect
66
+ INFO: 10.16.37.13:60532 - "GET /health HTTP/1.1" 200 OK
67
+ INFO: 10.16.37.13:24847 - "GET / HTTP/1.1" 200 OK
68
+ INFO: 10.16.13.79:43685 - "GET /health HTTP/1.1" 200 OK
69
+ INFO: 10.16.13.79:27030 - "GET /health HTTP/1.1" 200 OK
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/app/api/v1/contractor_invoices.py CHANGED
@@ -12,18 +12,19 @@ Contractor Invoice API Endpoints - Enterprise-Grade REST API
12
  ✅ Authorization checks
13
 
14
  **ENDPOINTS:**
15
- POST /invoices - Create new invoice
16
- GET /invoices/{id} - Get invoice by ID
17
- GET /invoices - List invoices (with filters)
18
- PUT /invoices/{id} - Update invoice (creates new version)
19
- DELETE /invoices/{id} - Soft delete invoice
20
- POST /invoices/{id}/line-items - Add line item
21
- DELETE /invoices/{id}/line-items/{line_item_id} - Remove line item
22
- PUT /invoices/{id}/line-items/{line_item_id} - Update line item
23
- POST /invoices/{id}/payments - Record payment
24
- PUT /invoices/{id}/status - Change status
25
- GET /invoices/{id}/versions - Get version history
26
- GET /invoices/{id}/versions/{version} - Get specific version
 
27
  """
28
  from fastapi import APIRouter, Depends, HTTPException, Query, status
29
  from sqlalchemy.orm import Session
@@ -44,7 +45,7 @@ router = APIRouter(tags=["Contractor Invoices"])
44
  # CREATE
45
  # ============================================
46
 
47
- @router.post("/", response_model=ContractorInvoiceResponse, status_code=status.HTTP_201_CREATED)
48
  def create_invoice(
49
  data: ContractorInvoiceCreate,
50
  db: Session = Depends(get_db),
@@ -187,7 +188,7 @@ def get_invoice(
187
  return ContractorInvoiceService.get_invoice_by_id(db, invoice_id, current_user)
188
 
189
 
190
- @router.get("/", response_model=List[ContractorInvoiceSummary])
191
  def list_invoices(
192
  contractor_id: Optional[UUID] = Query(None),
193
  client_id: Optional[UUID] = Query(None),
 
12
  ✅ Authorization checks
13
 
14
  **ENDPOINTS:**
15
+ POST /contractor-invoices - Create new invoice
16
+ GET /contractor-invoices/{id} - Get invoice by ID
17
+ GET /contractor-invoices - List invoices (with filters)
18
+ GET /contractor-invoices/stats - Get invoice statistics
19
+ PUT /contractor-invoices/{id} - Update invoice (creates new version)
20
+ DELETE /contractor-invoices/{id} - Soft delete invoice
21
+ POST /contractor-invoices/{id}/line-items - Add line item
22
+ DELETE /contractor-invoices/{id}/line-items/{line_item_id} - Remove line item
23
+ PUT /contractor-invoices/{id}/line-items/{line_item_id} - Update line item
24
+ POST /contractor-invoices/{id}/payments - Record payment
25
+ PUT /contractor-invoices/{id}/status - Change status
26
+ GET /contractor-invoices/{id}/versions - Get version history
27
+ GET /contractor-invoices/{id}/versions/{version} - Get specific version
28
  """
29
  from fastapi import APIRouter, Depends, HTTPException, Query, status
30
  from sqlalchemy.orm import Session
 
45
  # CREATE
46
  # ============================================
47
 
48
+ @router.post("", response_model=ContractorInvoiceResponse, status_code=status.HTTP_201_CREATED)
49
  def create_invoice(
50
  data: ContractorInvoiceCreate,
51
  db: Session = Depends(get_db),
 
188
  return ContractorInvoiceService.get_invoice_by_id(db, invoice_id, current_user)
189
 
190
 
191
+ @router.get("", response_model=List[ContractorInvoiceSummary])
192
  def list_invoices(
193
  contractor_id: Optional[UUID] = Query(None),
194
  client_id: Optional[UUID] = Query(None),