Rudraaaa76 commited on
Commit
6f69304
·
1 Parent(s): af00b15

added webhooks for jira

Browse files
.env.example DELETED
@@ -1,28 +0,0 @@
1
- # Mock Data Configuration
2
- USE_MOCK_DATA=False
3
-
4
- # Jira Configuration (OPTIONAL - only needed for mock/testing mode)
5
- # For production, users will provide these via /auth/login endpoint
6
- JIRA_SERVER_URL=https://yourcompany.atlassian.net
7
- JIRA_EMAIL=user@company.com
8
- JIRA_API_TOKEN=your_jira_api_token_here
9
-
10
- # Database
11
- DATABASE_URL=sqlite:///./enterprise_intelligence.db
12
-
13
- # Redis (Optional - for caching)
14
- REDIS_URL=redis://localhost:6379/0
15
-
16
- # API Configuration
17
- API_HOST=0.0.0.0
18
- API_PORT=8000
19
- DEBUG=True
20
-
21
- # Security (IMPORTANT: Change in production!)
22
- SECRET_KEY=your-secret-key-change-this-in-production-use-long-random-string
23
- ALGORITHM=HS256
24
- ACCESS_TOKEN_EXPIRE_MINUTES=30
25
-
26
- # GitHub Configuration (Optional)
27
- GITHUB_TOKEN=
28
- GITHUB_ORG=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
API_ENDPOINTS.md ADDED
@@ -0,0 +1,555 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # API Endpoints Reference
2
+
3
+ Complete reference for all API endpoints in the Enterprise Delivery & Workforce Intelligence API.
4
+
5
+ **Base URL (Hugging Face):** `https://rudraaaa76-jira-api.hf.space`
6
+ **Base URL (Local):** `http://localhost:8000`
7
+
8
+ **Authentication:** All endpoints (except `/auth/login`) require Bearer token authentication.
9
+
10
+ ---
11
+
12
+ ## Table of Contents
13
+
14
+ 1. [Authentication Endpoints](#authentication-endpoints)
15
+ 2. [Jira Data Endpoints](#jira-data-endpoints)
16
+ 3. [Intelligence & Analytics Endpoints](#intelligence--analytics-endpoints)
17
+
18
+ ---
19
+
20
+ ## Authentication Endpoints
21
+
22
+ ### POST /auth/login
23
+ **Description:** Authenticate with Jira credentials and receive JWT token
24
+ **Authentication:** None required
25
+ **Request Body:**
26
+ ```json
27
+ {
28
+ "jira_email": "rudraparmar1309@gmail.com",
29
+ "jira_api_token": "your_jira_api_token",
30
+ "jira_server_url": "https://rudraparmar1309-1770450259652.atlassian.net"
31
+ }
32
+ ```
33
+ **Response:**
34
+ ```json
35
+ {
36
+ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
37
+ "token_type": "bearer",
38
+ "expires_in": 1800
39
+ }
40
+ ```
41
+
42
+ ### GET /auth/me
43
+ **Description:** Get current authenticated user information
44
+ **Authentication:** Required
45
+ **Response:**
46
+ ```json
47
+ {
48
+ "jira_email": "rudraparmar1309@gmail.com",
49
+ "jira_server_url": "https://rudraparmar1309-1770450259652.atlassian.net",
50
+ "authenticated": true
51
+ }
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Jira Data Endpoints
57
+
58
+ ### Projects
59
+
60
+ #### GET /jira/projects
61
+ **Description:** Get all Jira projects
62
+ **Authentication:** Required
63
+ **Response:** Array of project objects
64
+ ```json
65
+ [
66
+ {
67
+ "project_key": "PROJ",
68
+ "project_name": "Project Name",
69
+ "project_id": "10000",
70
+ "lead": "User Name",
71
+ "description": "Project description"
72
+ }
73
+ ]
74
+ ```
75
+
76
+ #### GET /jira/projects/{project_key}/issues
77
+ **Description:** Get all issues for a specific project
78
+ **Authentication:** Required
79
+ **Path Parameters:**
80
+ - `project_key` (string) - Project key (e.g., "PROJ")
81
+
82
+ **Query Parameters:**
83
+ - `max_results` (integer, optional) - Maximum number of results (1-1000, default: 100)
84
+ - `start_date` (string, optional) - Filter from date (ISO format: YYYY-MM-DD)
85
+ - `end_date` (string, optional) - Filter to date (ISO format: YYYY-MM-DD)
86
+
87
+ **Example:** `/jira/projects/PROJ/issues?max_results=50&start_date=2026-01-01`
88
+
89
+ #### GET /jira/projects/{project_key}/team-members
90
+ **Description:** Get all team members for a project
91
+ **Authentication:** Required
92
+ **Path Parameters:**
93
+ - `project_key` (string) - Project key
94
+
95
+ **Response:** Array of team member objects
96
+
97
+ #### GET /jira/projects/{project_key}/worklogs
98
+ **Description:** Get worklogs for a project
99
+ **Authentication:** Required
100
+ **Path Parameters:**
101
+ - `project_key` (string) - Project key
102
+
103
+ **Query Parameters:**
104
+ - `start_date` (string, optional) - Start date (ISO format)
105
+ - `end_date` (string, optional) - End date (ISO format)
106
+
107
+ ### Boards
108
+
109
+ #### GET /jira/boards
110
+ **Description:** Get all Jira boards
111
+ **Authentication:** Required
112
+ **Response:** Array of board objects
113
+ ```json
114
+ [
115
+ {
116
+ "id": 1,
117
+ "name": "Board Name",
118
+ "type": "scrum",
119
+ "self": "https://..."
120
+ }
121
+ ]
122
+ ```
123
+
124
+ #### GET /jira/boards/{board_id}/sprints
125
+ **Description:** Get all sprints for a board
126
+ **Authentication:** Required
127
+ **Path Parameters:**
128
+ - `board_id` (integer) - Board ID
129
+
130
+ **Response:** Array of sprint objects
131
+
132
+ #### GET /jira/boards/{board_id}/active-sprint
133
+ **Description:** Get the currently active sprint for a board
134
+ **Authentication:** Required
135
+ **Path Parameters:**
136
+ - `board_id` (integer) - Board ID
137
+
138
+ **Response:** Sprint object or null
139
+
140
+ #### GET /jira/boards/{board_id}/configuration
141
+ **Description:** Get board configuration including columns and settings
142
+ **Authentication:** Required
143
+ **Path Parameters:**
144
+ - `board_id` (integer) - Board ID
145
+
146
+ #### GET /jira/boards/{board_id}/backlog
147
+ **Description:** Get backlog issues for a board
148
+ **Authentication:** Required
149
+ **Path Parameters:**
150
+ - `board_id` (integer) - Board ID
151
+
152
+ **Query Parameters:**
153
+ - `max_results` (integer, optional) - Maximum results (1-500, default: 100)
154
+
155
+ ### Sprints
156
+
157
+ #### GET /jira/sprints/{sprint_id}/issues
158
+ **Description:** Get all issues in a specific sprint
159
+ **Authentication:** Required
160
+ **Path Parameters:**
161
+ - `sprint_id` (integer) - Sprint ID
162
+
163
+ **Response:** Array of issue objects
164
+
165
+ ### Issues
166
+
167
+ #### GET /jira/issues/{issue_key}
168
+ **Description:** Get a specific issue by key
169
+ **Authentication:** Required
170
+ **Path Parameters:**
171
+ - `issue_key` (string) - Issue key (e.g., "PROJ-123")
172
+
173
+ **Response:** Issue object
174
+
175
+ #### GET /jira/issues/{issue_key}/transitions
176
+ **Description:** Get available transitions for an issue
177
+ **Authentication:** Required
178
+ **Path Parameters:**
179
+ - `issue_key` (string) - Issue key
180
+
181
+ **Response:** Array of transition objects
182
+
183
+ #### POST /jira/issues/{issue_key}/transition
184
+ **Description:** Move an issue to a different status
185
+ **Authentication:** Required
186
+ **Path Parameters:**
187
+ - `issue_key` (string) - Issue key
188
+
189
+ **Query Parameters:**
190
+ - `transition_name` (string, required) - Name of transition to execute
191
+
192
+ **Response:**
193
+ ```json
194
+ {
195
+ "success": true,
196
+ "message": "Issue PROJ-123 transitioned to Done"
197
+ }
198
+ ```
199
+
200
+ ### Kanban Boards
201
+
202
+ #### GET /jira/kanban/boards
203
+ **Description:** Get all Kanban boards with column configurations
204
+ **Authentication:** Required
205
+ **Response:** Array of Kanban board objects with columns
206
+
207
+ #### GET /jira/kanban/boards/{board_id}
208
+ **Description:** Get a specific Kanban board by ID
209
+ **Authentication:** Required
210
+ **Path Parameters:**
211
+ - `board_id` (integer) - Board ID
212
+
213
+ **Response:** Kanban board object with columns
214
+
215
+ #### GET /jira/kanban/boards/{board_id}/issues
216
+ **Description:** Get issues for a Kanban board grouped by columns
217
+ **Authentication:** Required
218
+ **Path Parameters:**
219
+ - `board_id` (integer) - Board ID
220
+
221
+ **Response:** Array of column objects with their issues
222
+
223
+ ---
224
+
225
+ ## Intelligence & Analytics Endpoints
226
+
227
+ ### Delivery Metrics
228
+
229
+ #### GET /intelligence/delivery-health/{project_key}
230
+ **Description:** Get delivery health metrics for a project or sprint
231
+ **Authentication:** Required
232
+ **Path Parameters:**
233
+ - `project_key` (string) - Project key
234
+
235
+ **Query Parameters:**
236
+ - `board_id` (integer, optional) - Board ID for sprint context
237
+ - `sprint_id` (integer, optional) - Specific sprint ID
238
+ - `start_date` (string, optional) - Start date (ISO format)
239
+ - `end_date` (string, optional) - End date (ISO format)
240
+
241
+ **Response:**
242
+ ```json
243
+ {
244
+ "velocity": 45.5,
245
+ "completion_rate": 87.5,
246
+ "avg_cycle_time_days": 3.2,
247
+ "sprint_health_score": 8.5,
248
+ "total_issues": 120,
249
+ "completed_issues": 105,
250
+ "in_progress_issues": 10,
251
+ "blocked_issues": 5
252
+ }
253
+ ```
254
+
255
+ ### Productivity Metrics
256
+
257
+ #### GET /intelligence/productivity/{project_key}
258
+ **Description:** Get productivity metrics for all team members
259
+ **Authentication:** Required
260
+ **Path Parameters:**
261
+ - `project_key` (string) - Project key
262
+
263
+ **Query Parameters:**
264
+ - `start_date` (string, optional) - Start date (default: 14 days ago)
265
+ - `end_date` (string, optional) - End date (default: today)
266
+
267
+ **Response:** Array of productivity metrics per team member
268
+ ```json
269
+ [
270
+ {
271
+ "team_member_id": "user123",
272
+ "team_member_name": "John Doe",
273
+ "issues_completed": 12,
274
+ "story_points_completed": 34,
275
+ "avg_completion_time_days": 2.5,
276
+ "work_hours_logged": 80,
277
+ "productivity_score": 8.7
278
+ }
279
+ ]
280
+ ```
281
+
282
+ ### Cost Efficiency
283
+
284
+ #### GET /intelligence/cost-efficiency/{project_key}
285
+ **Description:** Get cost efficiency metrics for a project
286
+ **Authentication:** Required
287
+ **Path Parameters:**
288
+ - `project_key` (string) - Project key
289
+
290
+ **Query Parameters:**
291
+ - `start_date` (string, optional) - Start date (default: 14 days ago)
292
+ - `end_date` (string, optional) - End date (default: today)
293
+ - `avg_hourly_rate` (float, optional) - Average hourly rate (default: 75.0)
294
+
295
+ **Response:**
296
+ ```json
297
+ {
298
+ "total_hours_logged": 520,
299
+ "total_cost": 39000,
300
+ "cost_per_issue": 325,
301
+ "cost_per_story_point": 162.5,
302
+ "efficiency_score": 7.8,
303
+ "issues_delivered": 120,
304
+ "story_points_delivered": 240
305
+ }
306
+ ```
307
+
308
+ ### Risk Management
309
+
310
+ #### GET /intelligence/risk-alerts/{project_key}
311
+ **Description:** Get risk alerts for a project
312
+ **Authentication:** Required
313
+ **Path Parameters:**
314
+ - `project_key` (string) - Project key
315
+
316
+ **Query Parameters:**
317
+ - `board_id` (integer, optional) - Board ID
318
+ - `sprint_id` (integer, optional) - Sprint ID
319
+ - `start_date` (string, optional) - Start date (default: 14 days ago)
320
+ - `end_date` (string, optional) - End date (default: today)
321
+
322
+ **Response:** Array of risk alert objects
323
+ ```json
324
+ [
325
+ {
326
+ "alert_type": "delivery_risk",
327
+ "severity": "high",
328
+ "title": "Sprint at Risk",
329
+ "description": "Sprint completion rate below 70%",
330
+ "affected_items": ["Sprint 42"],
331
+ "recommendation": "Review sprint scope and consider moving items to backlog"
332
+ }
333
+ ]
334
+ ```
335
+
336
+ ### Insights & Recommendations
337
+
338
+ #### GET /intelligence/insights/{project_key}
339
+ **Description:** Get AI-generated insights and recommendations
340
+ **Authentication:** Required
341
+ **Path Parameters:**
342
+ - `project_key` (string) - Project key
343
+
344
+ **Query Parameters:**
345
+ - `board_id` (integer, optional) - Board ID
346
+ - `sprint_id` (integer, optional) - Sprint ID
347
+ - `start_date` (string, optional) - Start date (default: 14 days ago)
348
+ - `end_date` (string, optional) - End date (default: today)
349
+
350
+ **Response:** Array of insight objects
351
+ ```json
352
+ [
353
+ {
354
+ "category": "productivity",
355
+ "priority": "high",
356
+ "title": "Optimize Team Allocation",
357
+ "description": "3 team members are over-allocated",
358
+ "impact": "Could improve delivery by 15%",
359
+ "action_items": ["Redistribute workload", "Review capacity planning"]
360
+ }
361
+ ]
362
+ ```
363
+
364
+ ### Dashboard
365
+
366
+ #### GET /intelligence/dashboard/{project_key}
367
+ **Description:** Get comprehensive dashboard data with all metrics
368
+ **Authentication:** Required
369
+ **Path Parameters:**
370
+ - `project_key` (string) - Project key
371
+
372
+ **Query Parameters:**
373
+ - `board_id` (integer, optional) - Board ID
374
+ - `sprint_id` (integer, optional) - Sprint ID
375
+ - `start_date` (string, optional) - Start date
376
+ - `end_date` (string, optional) - End date
377
+
378
+ **Response:** Combined object with all metrics
379
+ ```json
380
+ {
381
+ "delivery_health": {...},
382
+ "productivity_metrics": [...],
383
+ "cost_efficiency": {...},
384
+ "risk_alerts": [...],
385
+ "insights": [...],
386
+ "period": {
387
+ "start": "2026-01-24",
388
+ "end": "2026-02-07"
389
+ }
390
+ }
391
+ ```
392
+
393
+ ### Kanban Intelligence
394
+
395
+ #### GET /intelligence/kanban/flow-metrics/{board_id}
396
+ **Description:** Get Kanban flow efficiency metrics
397
+ **Authentication:** Required
398
+ **Path Parameters:**
399
+ - `board_id` (integer) - Board ID
400
+
401
+ **Query Parameters:**
402
+ - `start_date` (string, optional) - Start date (default: 30 days ago)
403
+ - `end_date` (string, optional) - End date (default: today)
404
+
405
+ **Response:**
406
+ ```json
407
+ {
408
+ "board_id": 123,
409
+ "board_name": "Development Board",
410
+ "cycle_time_avg_days": 4.5,
411
+ "lead_time_avg_days": 7.2,
412
+ "throughput": 25,
413
+ "wip_avg": 15,
414
+ "flow_efficiency": 62.5,
415
+ "blocked_items_count": 3
416
+ }
417
+ ```
418
+
419
+ #### GET /intelligence/kanban/column-analysis/{board_id}
420
+ **Description:** Get detailed analysis of each Kanban column
421
+ **Authentication:** Required
422
+ **Path Parameters:**
423
+ - `board_id` (integer) - Board ID
424
+
425
+ **Response:** Array of column analysis objects
426
+ ```json
427
+ [
428
+ {
429
+ "column_name": "In Progress",
430
+ "current_wip": 8,
431
+ "avg_time_in_column_days": 2.3,
432
+ "bottleneck_score": 6.5,
433
+ "issue_count": 8,
434
+ "recommended_wip_limit": 5
435
+ }
436
+ ]
437
+ ```
438
+
439
+ #### GET /intelligence/kanban/wip-recommendations/{board_id}
440
+ **Description:** Get WIP limit recommendations for columns
441
+ **Authentication:** Required
442
+ **Path Parameters:**
443
+ - `board_id` (integer) - Board ID
444
+
445
+ **Query Parameters:**
446
+ - `start_date` (string, optional) - Start date (default: 30 days ago)
447
+ - `end_date` (string, optional) - End date (default: today)
448
+
449
+ **Response:** Array of WIP recommendation objects
450
+ ```json
451
+ [
452
+ {
453
+ "column_name": "In Progress",
454
+ "current_wip": 8,
455
+ "current_limit": null,
456
+ "recommended_limit": 5,
457
+ "reason": "High average cycle time and bottleneck detected",
458
+ "expected_improvement": "Reduce cycle time by 25%"
459
+ }
460
+ ]
461
+ ```
462
+
463
+ #### GET /intelligence/kanban/insights/{board_id}
464
+ **Description:** Get Kanban-specific insights and recommendations
465
+ **Authentication:** Required
466
+ **Path Parameters:**
467
+ - `board_id` (integer) - Board ID
468
+
469
+ **Query Parameters:**
470
+ - `start_date` (string, optional) - Start date (default: 30 days ago)
471
+ - `end_date` (string, optional) - End date (default: today)
472
+
473
+ **Response:** Array of Kanban insight objects
474
+
475
+ #### GET /intelligence/kanban/dashboard/{board_id}
476
+ **Description:** Get comprehensive Kanban dashboard with all metrics
477
+ **Authentication:** Required
478
+ **Path Parameters:**
479
+ - `board_id` (integer) - Board ID
480
+
481
+ **Query Parameters:**
482
+ - `start_date` (string, optional) - Start date (default: 30 days ago)
483
+ - `end_date` (string, optional) - End date (default: today)
484
+
485
+ **Response:** Combined Kanban metrics object
486
+ ```json
487
+ {
488
+ "flow_metrics": {...},
489
+ "column_analysis": [...],
490
+ "wip_recommendations": [...],
491
+ "insights": [...],
492
+ "period": {
493
+ "start": "2026-01-08",
494
+ "end": "2026-02-07"
495
+ }
496
+ }
497
+ ```
498
+
499
+ ---
500
+
501
+ ## General Endpoints
502
+
503
+ ### GET /
504
+ **Description:** API root endpoint - returns API information
505
+ **Authentication:** None required
506
+ **Response:**
507
+ ```json
508
+ {
509
+ "message": "Enterprise Delivery & Workforce Intelligence API",
510
+ "version": "1.0.0",
511
+ "status": "operational",
512
+ "endpoints": {
513
+ "jira": "/jira",
514
+ "intelligence": "/intelligence",
515
+ "docs": "/docs",
516
+ "redoc": "/redoc"
517
+ }
518
+ }
519
+ ```
520
+
521
+ ### GET /health
522
+ **Description:** Health check endpoint
523
+ **Authentication:** None required
524
+ **Response:**
525
+ ```json
526
+ {
527
+ "status": "healthy",
528
+ "timestamp": "2026-02-07T00:00:00Z"
529
+ }
530
+ ```
531
+
532
+ ### GET /docs
533
+ **Description:** Interactive Swagger UI documentation
534
+ **Authentication:** None required (but needed to test endpoints)
535
+ **Browser:** Opens interactive API documentation
536
+
537
+ ### GET /redoc
538
+ **Description:** Alternative ReDoc API documentation
539
+ **Authentication:** None required
540
+ **Browser:** Opens ReDoc documentation
541
+
542
+ ---
543
+
544
+ ## Summary
545
+
546
+ **Total Endpoints:** 31
547
+
548
+ - **Authentication:** 2 endpoints
549
+ - **Jira Data:** 17 endpoints
550
+ - **Intelligence:** 10 endpoints
551
+ - **General:** 4 endpoints
552
+
553
+ **Authentication Method:** Bearer Token (JWT)
554
+ **Token Expiration:** 30 minutes
555
+ **Content Type:** application/json
API_USAGE.md DELETED
@@ -1,215 +0,0 @@
1
- # API Authentication Guide
2
-
3
- ## Overview
4
-
5
- The Enterprise Delivery & Workforce Intelligence API now requires user authentication. Each user must login with their own Jira credentials to access the API endpoints.
6
-
7
- ## How It Works
8
-
9
- 1. **Login**: Users authenticate with their Jira credentials
10
- 2. **Token**: System returns a JWT token valid for 30 minutes
11
- 3. **Access**: Use the token to access all protected endpoints
12
- 4. **Security**: Each user only sees data from their own Jira account
13
-
14
- ## Getting Started
15
-
16
- ### Step 1: Login
17
-
18
- Send a POST request to `/auth/login` with your Jira credentials:
19
-
20
- ```bash
21
- curl -X POST "http://localhost:8000/auth/login" \
22
- -H "Content-Type: application/json" \
23
- -d '{
24
- "jira_email": "your-email@company.com",
25
- "jira_api_token": "your-jira-api-token",
26
- "jira_server_url": "https://yourcompany.atlassian.net"
27
- }'
28
- ```
29
-
30
- **Response:**
31
- ```json
32
- {
33
- "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
34
- "token_type": "bearer",
35
- "expires_in": 1800
36
- }
37
- ```
38
-
39
- ### Step 2: Use the Token
40
-
41
- Include the token in the Authorization header for all subsequent requests:
42
-
43
- ```bash
44
- curl -X GET "http://localhost:8000/jira/projects" \
45
- -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
46
- ```
47
-
48
- ## Getting Your Jira API Token
49
-
50
- 1. Go to https://id.atlassian.com/manage-profile/security/api-tokens
51
- 2. Click **Create API token**
52
- 3. Give it a label (e.g., "Intelligence API")
53
- 4. Copy the token (you won't be able to see it again)
54
-
55
- ## Example Usage
56
-
57
- ### JavaScript/Fetch
58
-
59
- ```javascript
60
- // Login
61
- const loginResponse = await fetch('http://localhost:8000/auth/login', {
62
- method: 'POST',
63
- headers: { 'Content-Type': 'application/json' },
64
- body: JSON.stringify({
65
- jira_email: 'your-email@company.com',
66
- jira_api_token: 'your-jira-api-token',
67
- jira_server_url: 'https://yourcompany.atlassian.net'
68
- })
69
- });
70
-
71
- const { access_token } = await loginResponse.json();
72
-
73
- // Use the token
74
- const projectsResponse = await fetch('http://localhost:8000/jira/projects', {
75
- headers: { 'Authorization': `Bearer ${access_token}` }
76
- });
77
-
78
- const projects = await projectsResponse.json();
79
- ```
80
-
81
- ### Python
82
-
83
- ```python
84
- import requests
85
-
86
- # Login
87
- login_response = requests.post('http://localhost:8000/auth/login', json={
88
- 'jira_email': 'your-email@company.com',
89
- 'jira_api_token': 'your-jira-api-token',
90
- 'jira_server_url': 'https://yourcompany.atlassian.net'
91
- })
92
-
93
- token = login_response.json()['access_token']
94
-
95
- # Use the token
96
- headers = {'Authorization': f'Bearer {token}'}
97
- projects_response = requests.get('http://localhost:8000/jira/projects', headers=headers)
98
- projects = projects_response.json()
99
- ```
100
-
101
- ### curl Examples
102
-
103
- ```bash
104
- # 1. Login and save token
105
- TOKEN=$(curl -s -X POST "http://localhost:8000/auth/login" \
106
- -H "Content-Type: application/json" \
107
- -d '{
108
- "jira_email": "your-email@company.com",
109
- "jira_api_token": "your-jira-api-token",
110
- "jira_server_url": "https://yourcompany.atlassian.net"
111
- }' | jq -r '.access_token')
112
-
113
- # 2. Get projects
114
- curl -X GET "http://localhost:8000/jira/projects" \
115
- -H "Authorization: Bearer $TOKEN"
116
-
117
- # 3. Get delivery health metrics
118
- curl -X GET "http://localhost:8000/intelligence/delivery-health/PROJ" \
119
- -H "Authorization: Bearer $TOKEN"
120
-
121
- # 4. Get Kanban boards
122
- curl -X GET "http://localhost:8000/jira/kanban/boards" \
123
- -H "Authorization: Bearer $TOKEN"
124
- ```
125
-
126
- ## Token Management
127
-
128
- ### Token Expiration
129
-
130
- - Tokens expire after **30 minutes** by default
131
- - When a token expires, you'll receive a `401 Unauthorized` response
132
- - Simply login again to get a new token
133
-
134
- ### Checking Token Validity
135
-
136
- Verify your current token:
137
-
138
- ```bash
139
- curl -X GET "http://localhost:8000/auth/me" \
140
- -H "Authorization: Bearer $TOKEN"
141
- ```
142
-
143
- **Response:**
144
- ```json
145
- {
146
- "jira_email": "your-email@company.com",
147
- "jira_server_url": "https://yourcompany.atlassian.net",
148
- "authenticated": true
149
- }
150
- ```
151
-
152
- ## API Endpoints
153
-
154
- All endpoints now require authentication. Here are the main endpoint categories:
155
-
156
- ### Authentication (`/auth`)
157
- - `POST /auth/login` - Login with Jira credentials
158
- - `GET /auth/me` - Get current user info
159
-
160
- ### Jira Data (`/jira`)
161
- - `GET /jira/projects` - List all projects
162
- - `GET /jira/boards` - List all boards
163
- - `GET /jira/projects/{project_key}/issues` - Get project issues
164
- - `GET /jira/boards/{board_id}/sprints` - Get board sprints
165
- - `GET /jira/kanban/boards` - Get Kanban boards
166
- - And more...
167
-
168
- ### Intelligence (`/intelligence`)
169
- - `GET /intelligence/delivery-health/{project_key}` - Delivery metrics
170
- - `GET /intelligence/productivity/{project_key}` - Productivity metrics
171
- - `GET /intelligence/risk-alerts/{project_key}` - Risk alerts
172
- - `GET /intelligence/kanban/flow-metrics/{board_id}` - Kanban metrics
173
- - And more...
174
-
175
- ## Interactive API Documentation
176
-
177
- Visit http://localhost:8000/docs for interactive Swagger documentation where you can:
178
- 1. Click the **Authorize** button
179
- 2. Enter your token as: `Bearer your-token-here`
180
- 3. Try out all endpoints interactively
181
-
182
- ## Security Notes
183
-
184
- - **Never commit credentials**: Don't store API tokens in code or version control
185
- - **Use environment variables**: Store tokens in environment variables or secure vaults
186
- - **HTTPS in production**: Always use HTTPS in production environments
187
- - **Token security**: Treat JWT tokens like passwords - keep them secret
188
-
189
- ## Troubleshooting
190
-
191
- ### 401 Unauthorized
192
- - Token expired: Login again to get a new token
193
- - Invalid token: Check that you're using the correct format: `Bearer {token}`
194
- - Missing token: Ensure the Authorization header is included
195
-
196
- ### 403 Forbidden
197
- - Invalid Jira credentials: Check your Jira email and API token
198
- - Insufficient permissions: Verify you have access to the Jira resources
199
-
200
- ### Token Validation Failed
201
- - Token format error: Ensure token is properly formatted JWT
202
- - Expired token: Login again to refresh your token
203
-
204
- ## Migration from .env Setup
205
-
206
- Previously, the API used credentials from the `.env` file. Now:
207
-
208
- - ❌ **Old**: Credentials in `.env` file (shared by all users)
209
- - ✅ **New**: Each user provides their own credentials via login
210
-
211
- This change provides:
212
- - **Better security**: No shared credentials
213
- - **User-specific data**: Each user sees only their Jira data
214
- - **Audit trail**: Track which user made which requests
215
- - **Better compliance**: Aligns with enterprise security policies
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
api/webhook_routes.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Header, Request, HTTPException
2
+ import logging
3
+ from services.supabase_service import supabase_service
4
+ from typing import Dict, Any
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ router = APIRouter(prefix="/webhooks/jira", tags=["Webhooks"])
9
+
10
+ @router.post("")
11
+ async def receive_jira_webhook(
12
+ request: Request,
13
+ x_atlassian_webhook_identifier: str = Header(None)
14
+ ):
15
+ """
16
+ Receive webhook events from Jira
17
+ """
18
+ try:
19
+ payload = await request.json()
20
+ logger.info(f"Received Jira webhook: {x_atlassian_webhook_identifier}")
21
+
22
+ # Determine the user email from the payload
23
+ user_email = None
24
+
25
+ # 1. Update issue event
26
+ if "issue" in payload:
27
+ issue = payload["issue"]
28
+ # Try assignee first
29
+ if issue.get("fields", {}).get("assignee"):
30
+ user_email = issue["fields"]["assignee"].get("emailAddress")
31
+ # Fallback to reporter
32
+ if not user_email and issue.get("fields", {}).get("reporter"):
33
+ user_email = issue["fields"]["reporter"].get("emailAddress")
34
+
35
+ # 2. User created/updated event
36
+ elif "user" in payload:
37
+ user_email = payload["user"].get("emailAddress")
38
+
39
+ if not user_email:
40
+ logger.warning("Could not identify user email from webhook payload")
41
+ # We still return 200 to Jira so it doesn't retry
42
+ return {"status": "ignored", "reason": "no_email_found"}
43
+
44
+ # Find user in Supabase
45
+ firebase_id = supabase_service.get_user_id_by_email(user_email)
46
+
47
+ if not firebase_id:
48
+ logger.warning(f"No Supabase user found for Jira email: {user_email}")
49
+ return {"status": "ignored", "reason": "user_not_found"}
50
+
51
+ # Store data
52
+ success = supabase_service.upsert_jira_data(firebase_id, payload)
53
+
54
+ if success:
55
+ return {"status": "processed", "user": firebase_id}
56
+ else:
57
+ raise HTTPException(status_code=500, detail="Failed to store data")
58
+
59
+ except Exception as e:
60
+ logger.error(f"Error processing webhook: {str(e)}")
61
+ raise HTTPException(status_code=500, detail=str(e))
config/settings.py CHANGED
@@ -18,6 +18,10 @@ class Settings(BaseSettings):
18
  # Database
19
  database_url: str = "sqlite:///./enterprise_intelligence.db"
20
 
 
 
 
 
21
  # Redis
22
  redis_url: str = "redis://localhost:6379/0"
23
 
 
18
  # Database
19
  database_url: str = "sqlite:///./enterprise_intelligence.db"
20
 
21
+ # Supabase
22
+ supabase_url: Optional[str] = None
23
+ supabase_key: Optional[str] = None
24
+
25
  # Redis
26
  redis_url: str = "redis://localhost:6379/0"
27
 
main.py CHANGED
@@ -3,6 +3,7 @@ from fastapi.middleware.cors import CORSMiddleware
3
  from api.auth_routes import router as auth_router
4
  from api.jira_routes import router as jira_router
5
  from api.intelligence_routes import router as intelligence_router
 
6
  from config.settings import settings
7
  import logging
8
 
@@ -35,6 +36,7 @@ app.add_middleware(
35
  app.include_router(auth_router)
36
  app.include_router(jira_router)
37
  app.include_router(intelligence_router)
 
38
 
39
 
40
  @app.get("/")
 
3
  from api.auth_routes import router as auth_router
4
  from api.jira_routes import router as jira_router
5
  from api.intelligence_routes import router as intelligence_router
6
+ from api.webhook_routes import router as webhook_router
7
  from config.settings import settings
8
  import logging
9
 
 
36
  app.include_router(auth_router)
37
  app.include_router(jira_router)
38
  app.include_router(intelligence_router)
39
+ app.include_router(webhook_router)
40
 
41
 
42
  @app.get("/")
requirements.txt CHANGED
@@ -3,7 +3,7 @@ uvicorn==0.27.0
3
  pydantic==2.5.3
4
  pydantic-settings==2.1.0
5
  jira==3.8.0
6
- httpx==0.26.0
7
  python-dotenv==1.0.0
8
  pandas==2.1.4
9
  numpy==1.26.3
@@ -15,3 +15,4 @@ passlib[bcrypt]==1.7.4
15
  python-multipart==0.0.6
16
  aiohttp==3.9.1
17
  pydantic[email]
 
 
3
  pydantic==2.5.3
4
  pydantic-settings==2.1.0
5
  jira==3.8.0
6
+ httpx
7
  python-dotenv==1.0.0
8
  pandas==2.1.4
9
  numpy==1.26.3
 
15
  python-multipart==0.0.6
16
  aiohttp==3.9.1
17
  pydantic[email]
18
+ supabase==2.3.4
services/supabase_service.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from supabase import create_client, Client
2
+ from config.settings import settings
3
+ import logging
4
+ from typing import Optional, Dict, Any
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ class SupabaseService:
9
+ """Service to handle Supabase database operations"""
10
+
11
+ def __init__(self):
12
+ self.client: Optional[Client] = None
13
+ if settings.supabase_url and settings.supabase_key:
14
+ try:
15
+ self.client = create_client(settings.supabase_url, settings.supabase_key)
16
+ logger.info("Supabase client initialized successfully")
17
+ except Exception as e:
18
+ logger.error(f"Failed to initialize Supabase client: {str(e)}")
19
+ else:
20
+ logger.warning("Supabase URL or Key not found in settings. Supabase integration disabled.")
21
+
22
+ def get_user_id_by_email(self, email: str) -> Optional[str]:
23
+ """
24
+ Find user's firebase_id by email from the Users table
25
+ """
26
+ if not self.client:
27
+ logger.warning("Supabase client not initialized")
28
+ return None
29
+
30
+ try:
31
+ # Assuming the table name is "Users" and it has "email" and "firebase_id" columns
32
+ response = self.client.table("Users").select("firebase_id").eq("email", email).execute()
33
+
34
+ if response.data and len(response.data) > 0:
35
+ return response.data[0]["firebase_id"]
36
+ return None
37
+
38
+ except Exception as e:
39
+ logger.error(f"Error fetching user by email {email}: {str(e)}")
40
+ return None
41
+
42
+ def upsert_jira_data(self, firebase_id: str, data: Dict[str, Any]) -> bool:
43
+ """
44
+ Insert or update Jira data for a user
45
+ """
46
+ if not self.client:
47
+ logger.warning("Supabase client not initialized")
48
+ return False
49
+
50
+ try:
51
+ # Prepare payload
52
+ payload = {
53
+ "user_id": firebase_id,
54
+ "jira_payload": data,
55
+ "updated_at": "now()"
56
+ }
57
+
58
+ # Upsert into jira_data table
59
+ # Note: The table needs to conflict on user_id if we want 1 row per user,
60
+ # or we just insert a new log every time.
61
+ # Given "store all the data", let's assume we want a log of events.
62
+ # But the user also said "data gets updated".
63
+ # Let's insert a new record for every event for now to be safe (Audit Log style).
64
+ # AND/OR update a current state record.
65
+ # For simplicity let's insert a new record.
66
+
67
+ self.client.table("jira_data").insert(payload).execute()
68
+ logger.info(f"Successfully stored Jira data for user {firebase_id}")
69
+ return True
70
+
71
+ except Exception as e:
72
+ logger.error(f"Error storing Jira data for {firebase_id}: {str(e)}")
73
+ return False
74
+
75
+ # Create singleton
76
+ supabase_service = SupabaseService()