@equilateral_ai/mindmeld 3.5.2 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/hooks/session-end.js +25 -0
  2. package/hooks/session-start.js +363 -83
  3. package/hooks/session-watcher.js +585 -0
  4. package/package.json +19 -13
  5. package/scripts/init-project.js +9 -23
  6. package/src/client/dbShim.js +16 -0
  7. package/src/core/AuthManager.js +3 -2
  8. package/src/handlers/helpers/dbOperations.js +9 -46
  9. package/src/index.js +2 -217
  10. package/src/utils/piiMask.js +16 -0
  11. package/scripts/harvest.js +0 -601
  12. package/scripts/inject.js +0 -409
  13. package/scripts/mcp-bridge.js +0 -220
  14. package/scripts/repo-analyzer.js +0 -870
  15. package/src/collaboration/CollaborationPrompt.js +0 -460
  16. package/src/core/AlertEngine.js +0 -813
  17. package/src/core/AlertNotifier.js +0 -363
  18. package/src/core/CorrelationAnalyzer.js +0 -931
  19. package/src/core/CrossReferenceEngine.js +0 -624
  20. package/src/core/CurationEngine.js +0 -688
  21. package/src/core/DeprecationScheduler.js +0 -183
  22. package/src/core/LoadBearingDetector.js +0 -242
  23. package/src/core/NotificationService.js +0 -1032
  24. package/src/core/RapportOrchestrator.js +0 -632
  25. package/src/core/RelevanceDetector.js +0 -694
  26. package/src/core/StandardLifecycle.js +0 -244
  27. package/src/core/StandardsIngestion.js +0 -991
  28. package/src/core/TeamLoadBearingDetector.js +0 -431
  29. package/src/core/parsers/adrParser.js +0 -479
  30. package/src/core/parsers/cursorRulesParser.js +0 -564
  31. package/src/core/parsers/eslintParser.js +0 -439
  32. package/src/database/dbOperations.js +0 -105
  33. package/src/handlers/activity/activityGetMe.js +0 -98
  34. package/src/handlers/activity/activityGetTeam.js +0 -175
  35. package/src/handlers/admin/adminSetup.js +0 -216
  36. package/src/handlers/alerts/alertsAcknowledge.js +0 -92
  37. package/src/handlers/alerts/alertsGet.js +0 -250
  38. package/src/handlers/analytics/activitySummaryGet.js +0 -234
  39. package/src/handlers/analytics/coachingGet.js +0 -361
  40. package/src/handlers/analytics/convergenceGet.js +0 -236
  41. package/src/handlers/analytics/developerScoreGet.js +0 -137
  42. package/src/handlers/collaborators/collaboratorAdd.js +0 -200
  43. package/src/handlers/collaborators/collaboratorInvite.js +0 -219
  44. package/src/handlers/collaborators/collaboratorList.js +0 -82
  45. package/src/handlers/collaborators/collaboratorRemove.js +0 -128
  46. package/src/handlers/collaborators/inviteAccept.js +0 -122
  47. package/src/handlers/company/companyUsersDelete.js +0 -141
  48. package/src/handlers/company/companyUsersGet.js +0 -90
  49. package/src/handlers/company/companyUsersPost.js +0 -267
  50. package/src/handlers/company/companyUsersPut.js +0 -76
  51. package/src/handlers/context/contextGet.js +0 -57
  52. package/src/handlers/context/invariantsGet.js +0 -74
  53. package/src/handlers/context/loopsGet.js +0 -82
  54. package/src/handlers/context/notesCreate.js +0 -74
  55. package/src/handlers/context/purposeGet.js +0 -78
  56. package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
  57. package/src/handlers/correlations/correlationsGet.js +0 -93
  58. package/src/handlers/correlations/correlationsProjectGet.js +0 -153
  59. package/src/handlers/enterprise/controlTowerGet.js +0 -224
  60. package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
  61. package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
  62. package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
  63. package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
  64. package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
  65. package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
  66. package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
  67. package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
  68. package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
  69. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
  70. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
  71. package/src/handlers/github/githubConnectionStatus.js +0 -49
  72. package/src/handlers/github/githubDiscoverPatterns.js +0 -621
  73. package/src/handlers/github/githubOAuthCallback.js +0 -178
  74. package/src/handlers/github/githubOAuthStart.js +0 -59
  75. package/src/handlers/github/githubPatternsReview.js +0 -76
  76. package/src/handlers/github/githubReposList.js +0 -105
  77. package/src/handlers/health/healthGet.js +0 -55
  78. package/src/handlers/helpers/auditLogger.js +0 -201
  79. package/src/handlers/helpers/checkSuperAdmin.js +0 -84
  80. package/src/handlers/helpers/decisionFrames.js +0 -29
  81. package/src/handlers/helpers/errorHandler.js +0 -49
  82. package/src/handlers/helpers/index.js +0 -138
  83. package/src/handlers/helpers/lambdaWrapper.js +0 -60
  84. package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
  85. package/src/handlers/helpers/predictiveCache.js +0 -51
  86. package/src/handlers/helpers/projectAccess.js +0 -88
  87. package/src/handlers/helpers/responseUtil.js +0 -55
  88. package/src/handlers/helpers/subscriptionTiers.js +0 -1168
  89. package/src/handlers/mcp/mcpHandler.js +0 -569
  90. package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
  91. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
  92. package/src/handlers/notifications/getPreferences.js +0 -84
  93. package/src/handlers/notifications/sendNotification.js +0 -170
  94. package/src/handlers/notifications/updatePreferences.js +0 -316
  95. package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
  96. package/src/handlers/patterns/patternUsagePost.js +0 -182
  97. package/src/handlers/patterns/patternViolationPost.js +0 -185
  98. package/src/handlers/projects/projectCreate.js +0 -248
  99. package/src/handlers/projects/projectDelete.js +0 -82
  100. package/src/handlers/projects/projectGet.js +0 -95
  101. package/src/handlers/projects/projectUpdate.js +0 -117
  102. package/src/handlers/reports/aiLeverage.js +0 -210
  103. package/src/handlers/reports/engineeringInvestment.js +0 -132
  104. package/src/handlers/reports/riskForecast.js +0 -206
  105. package/src/handlers/reports/standardsRoi.js +0 -254
  106. package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
  107. package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
  108. package/src/handlers/scheduled/generateAlerts.js +0 -135
  109. package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
  110. package/src/handlers/scheduled/refreshActivity.js +0 -21
  111. package/src/handlers/scheduled/scanCompliance.js +0 -334
  112. package/src/handlers/sessions/sessionEndPost.js +0 -180
  113. package/src/handlers/sessions/sessionStandardsPost.js +0 -171
  114. package/src/handlers/standards/catalogGet.js +0 -185
  115. package/src/handlers/standards/catalogSync.js +0 -120
  116. package/src/handlers/standards/discoveriesGet.js +0 -89
  117. package/src/handlers/standards/projectStandardsGet.js +0 -129
  118. package/src/handlers/standards/projectStandardsPut.js +0 -151
  119. package/src/handlers/standards/standardsAuditGet.js +0 -65
  120. package/src/handlers/standards/standardsParseUpload.js +0 -149
  121. package/src/handlers/standards/standardsRelevantPost.js +0 -405
  122. package/src/handlers/standards/standardsTransition.js +0 -161
  123. package/src/handlers/stripe/addonManagePost.js +0 -240
  124. package/src/handlers/stripe/billingPortalPost.js +0 -93
  125. package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
  126. package/src/handlers/stripe/seatsUpdatePost.js +0 -185
  127. package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
  128. package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
  129. package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
  130. package/src/handlers/stripe/webhookPost.js +0 -482
  131. package/src/handlers/user/apiTokenCreate.js +0 -71
  132. package/src/handlers/user/apiTokenList.js +0 -64
  133. package/src/handlers/user/userSplashAck.js +0 -91
  134. package/src/handlers/user/userSplashGet.js +0 -211
  135. package/src/handlers/users/cognitoPostConfirmation.js +0 -186
  136. package/src/handlers/users/cognitoPreSignUp.js +0 -114
  137. package/src/handlers/users/userEntitlementsGet.js +0 -89
  138. package/src/handlers/users/userGet.js +0 -118
  139. package/src/handlers/users/userProfilePut.js +0 -77
  140. package/src/handlers/webhooks/githubWebhook.js +0 -215
@@ -1,250 +0,0 @@
1
- /**
2
- * Alerts Get Handler
3
- * Retrieves attention alerts (own alerts or team alerts for managers)
4
- *
5
- * GET /api/alerts
6
- * Auth: Cognito JWT required
7
- *
8
- * Query Parameters:
9
- * - status: 'active' (default), 'acknowledged', 'resolved', or 'all'
10
- * - type: Filter by alert type (optional)
11
- * - severity: Filter by severity (optional)
12
- */
13
-
14
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
15
-
16
- exports.handler = wrapHandler(async ({ requestContext, queryStringParameters }) => {
17
- const Request_ID = requestContext.requestId;
18
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
19
-
20
- if (!email) {
21
- return createErrorResponse(401, 'Authentication required');
22
- }
23
-
24
- // Check user role
25
- const userCheck = await executeQuery(`
26
- SELECT
27
- ue.company_id,
28
- ue.manager,
29
- ue.admin,
30
- u.super_admin
31
- FROM rapport.user_entitlements ue
32
- JOIN rapport.users u ON ue.email_address = u.email_address
33
- WHERE ue.email_address = $1
34
- `, [email]);
35
-
36
- if (userCheck.rowCount === 0) {
37
- return createErrorResponse(403, 'Access denied');
38
- }
39
-
40
- const userRole = userCheck.rows[0];
41
- const isManager = userRole.manager || userRole.admin || userRole.super_admin;
42
- const companyId = userRole.company_id;
43
-
44
- // Parse query parameters
45
- const status = queryStringParameters?.status || 'active';
46
- const alertType = queryStringParameters?.type || null;
47
- const severity = queryStringParameters?.severity || null;
48
-
49
- let result;
50
-
51
- if (isManager) {
52
- // Get team alerts with optional filters
53
- let query = `
54
- SELECT
55
- aa.alert_id,
56
- aa.email_address,
57
- CONCAT(u.first_name, ' ', u.last_name) as user_name,
58
- aa.alert_type,
59
- aa.severity,
60
- aa.details,
61
- aa.status,
62
- aa.acknowledged_by,
63
- aa.acknowledged_at,
64
- aa.expires_at,
65
- aa.created_at
66
- FROM rapport.attention_alerts aa
67
- JOIN rapport.users u ON aa.email_address = u.email_address
68
- WHERE aa.company_id = $1
69
- `;
70
-
71
- const params = [companyId];
72
- let paramIndex = 2;
73
-
74
- // Status filter
75
- if (status !== 'all') {
76
- query += ` AND aa.status = $${paramIndex}`;
77
- params.push(status);
78
- paramIndex++;
79
- }
80
-
81
- // Alert type filter
82
- if (alertType) {
83
- query += ` AND aa.alert_type = $${paramIndex}`;
84
- params.push(alertType);
85
- paramIndex++;
86
- }
87
-
88
- // Severity filter
89
- if (severity) {
90
- query += ` AND aa.severity = $${paramIndex}`;
91
- params.push(severity);
92
- paramIndex++;
93
- }
94
-
95
- // Order by severity (critical > warning > info) then by date
96
- query += `
97
- ORDER BY
98
- CASE aa.severity
99
- WHEN 'critical' THEN 1
100
- WHEN 'warning' THEN 2
101
- ELSE 3
102
- END,
103
- aa.created_at DESC
104
- `;
105
-
106
- result = await executeQuery(query, params);
107
- } else {
108
- // Get own alerts only
109
- let query = `
110
- SELECT
111
- aa.alert_id,
112
- aa.email_address,
113
- aa.alert_type,
114
- aa.severity,
115
- aa.details,
116
- aa.status,
117
- aa.expires_at,
118
- aa.created_at
119
- FROM rapport.attention_alerts aa
120
- WHERE aa.email_address = $1
121
- `;
122
-
123
- const params = [email];
124
- let paramIndex = 2;
125
-
126
- if (status !== 'all') {
127
- query += ` AND aa.status = $${paramIndex}`;
128
- params.push(status);
129
- paramIndex++;
130
- }
131
-
132
- if (alertType) {
133
- query += ` AND aa.alert_type = $${paramIndex}`;
134
- params.push(alertType);
135
- paramIndex++;
136
- }
137
-
138
- if (severity) {
139
- query += ` AND aa.severity = $${paramIndex}`;
140
- params.push(severity);
141
- paramIndex++;
142
- }
143
-
144
- query += ` ORDER BY aa.created_at DESC`;
145
-
146
- result = await executeQuery(query, params);
147
- }
148
-
149
- const alerts = result.rows.map(alert => ({
150
- alert_id: alert.alert_id,
151
- email_address: alert.email_address,
152
- user_name: alert.user_name || null,
153
- alert_type: alert.alert_type,
154
- severity: alert.severity,
155
- details: alert.details,
156
- status: alert.status,
157
- acknowledged_by: alert.acknowledged_by || null,
158
- acknowledged_at: alert.acknowledged_at || null,
159
- expires_at: alert.expires_at || null,
160
- created_at: alert.created_at,
161
- message: getAlertMessage(alert.alert_type, alert.details),
162
- recommendation: getAlertRecommendation(alert.alert_type, alert.severity)
163
- }));
164
-
165
- // Calculate summary statistics
166
- const summary = {
167
- total: alerts.length,
168
- by_severity: {
169
- critical: alerts.filter(a => a.severity === 'critical').length,
170
- warning: alerts.filter(a => a.severity === 'warning').length,
171
- info: alerts.filter(a => a.severity === 'info').length
172
- },
173
- by_type: {}
174
- };
175
-
176
- for (const alert of alerts) {
177
- summary.by_type[alert.alert_type] = (summary.by_type[alert.alert_type] || 0) + 1;
178
- }
179
-
180
- return createSuccessResponse(
181
- { Records: alerts, summary, is_manager_view: isManager },
182
- 'Alerts retrieved',
183
- { Total_Records: alerts.length, Request_ID, Timestamp: new Date().toISOString() }
184
- );
185
- });
186
-
187
- /**
188
- * Generate human-readable message for alert
189
- */
190
- function getAlertMessage(alertType, details) {
191
- switch (alertType) {
192
- case 'stale_commits':
193
- return `No commits in ${details.days_since_commit} days`;
194
-
195
- case 'low_conversion':
196
- return `Low session-to-commit conversion: ${details.conversion_pct}%`;
197
-
198
- case 'no_ai_usage':
199
- return `Active committer not using AI assistance (${details.commits_30d} commits, 0 sessions)`;
200
-
201
- case 'high_violation_rate':
202
- return `High standards violation rate: ${details.violation_rate}% (${details.violations}/${details.standards_shown})`;
203
-
204
- case 'stalled_patterns':
205
- return `Stalled patterns: ${details.stale_patterns} patterns unused, ${details.provisional_patterns} stuck in provisional`;
206
-
207
- case 'declining_activity':
208
- const decline = details.decline_pct || 0;
209
- return `Activity declined ${decline}% (was ${details.avg_previous_weeks} sessions/week, now ${details.current_week})`;
210
-
211
- default:
212
- return `Alert: ${alertType}`;
213
- }
214
- }
215
-
216
- /**
217
- * Generate actionable recommendation for alert
218
- */
219
- function getAlertRecommendation(alertType, severity) {
220
- const recommendations = {
221
- stale_commits: {
222
- critical: 'Schedule a 1:1 to check in on progress and identify blockers',
223
- warning: 'Consider reaching out to offer assistance',
224
- info: 'Monitor for continued inactivity'
225
- },
226
- low_conversion: {
227
- critical: 'Review session recordings to identify workflow issues',
228
- warning: 'Check if developer needs additional training on AI tools',
229
- info: 'Provide tips for effective AI-assisted development'
230
- },
231
- no_ai_usage: {
232
- info: 'Share AI adoption resources and success stories from team'
233
- },
234
- high_violation_rate: {
235
- critical: 'Schedule standards review session with developer',
236
- warning: 'Share relevant standards documentation',
237
- info: 'Consider adding standards to onboarding materials'
238
- },
239
- stalled_patterns: {
240
- warning: 'Review patterns for promotion or deprecation',
241
- info: 'Encourage pattern documentation and sharing'
242
- },
243
- declining_activity: {
244
- warning: 'Check in on workload and well-being',
245
- info: 'Monitor for continued decline'
246
- }
247
- };
248
-
249
- return recommendations[alertType]?.[severity] || recommendations[alertType]?.info || 'Monitor and follow up as needed';
250
- }
@@ -1,234 +0,0 @@
1
- /**
2
- * Activity Summary Get Handler
3
- * Aggregates activity metrics for analytics dashboards
4
- *
5
- * GET /api/analytics/activity-summary
6
- * Auth: Cognito JWT required
7
- *
8
- * Query Parameters:
9
- * - project_id (optional): filter to a specific project
10
- * - period: 7d | 30d | 90d (default: 7d)
11
- *
12
- * Returns harvests, injections, promotions, violations, and top standards
13
- * broken down by day and category.
14
- */
15
-
16
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
17
-
18
- async function getActivitySummary({ requestContext, queryStringParameters }) {
19
- const Request_ID = requestContext.requestId;
20
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
21
-
22
- if (!email) {
23
- return createErrorResponse(401, 'Authentication required');
24
- }
25
-
26
- // Verify user access
27
- const userCheck = await executeQuery(`
28
- SELECT ue.company_id
29
- FROM rapport.user_entitlements ue
30
- WHERE ue.email_address = $1
31
- LIMIT 1
32
- `, [email]);
33
-
34
- if (userCheck.rowCount === 0) {
35
- return createErrorResponse(403, 'Access denied');
36
- }
37
-
38
- const companyId = userCheck.rows[0].company_id;
39
- const params = queryStringParameters || {};
40
- const projectId = params.project_id || null;
41
- const period = params.period || '7d';
42
-
43
- const periodDays = parsePeriod(period);
44
- const periodStart = new Date();
45
- periodStart.setDate(periodStart.getDate() - periodDays);
46
-
47
- // Build project filter clause
48
- const projectFilter = projectId ? 'AND at.project_id = $3' : '';
49
- const baseParams = projectId
50
- ? [companyId, periodStart.toISOString(), projectId]
51
- : [companyId, periodStart.toISOString()];
52
-
53
- // Harvests: patterns created in the period
54
- let harvests = { total: 0, by_day: [] };
55
- try {
56
- const harvestResult = await executeQuery(`
57
- SELECT
58
- DATE(p.created_at) as date,
59
- COUNT(*) as count
60
- FROM rapport.patterns p
61
- JOIN rapport.user_entitlements ue ON p.created_by = ue.email_address
62
- WHERE ue.company_id = $1
63
- AND p.created_at >= $2
64
- ${projectId ? 'AND p.project_id = $3' : ''}
65
- GROUP BY DATE(p.created_at)
66
- ORDER BY date
67
- `, baseParams);
68
-
69
- const byDay = harvestResult.rows.map(row => ({
70
- date: row.date,
71
- count: parseInt(row.count, 10)
72
- }));
73
- const total = byDay.reduce((sum, d) => sum + d.count, 0);
74
- harvests = { total, by_day: byDay };
75
- } catch (err) {
76
- console.log('[ActivitySummary] Harvests query failed:', err.message);
77
- }
78
-
79
- // Injections: count from session_standards joined through sessions
80
- let injections = { total: 0, by_day: [] };
81
- try {
82
- const injectionResult = await executeQuery(`
83
- SELECT
84
- DATE(ss.created_at) as date,
85
- COUNT(*) as count
86
- FROM rapport.session_standards ss
87
- JOIN rapport.sessions s ON s.session_id = ss.session_id
88
- JOIN rapport.user_entitlements ue ON s.email_address = ue.email_address
89
- WHERE ue.company_id = $1
90
- AND ss.created_at >= $2
91
- ${projectId ? 'AND s.project_id = $3' : ''}
92
- GROUP BY DATE(ss.created_at)
93
- ORDER BY date
94
- `, baseParams);
95
-
96
- const byDay = injectionResult.rows.map(row => ({
97
- date: row.date,
98
- count: parseInt(row.count, 10)
99
- }));
100
- const total = byDay.reduce((sum, d) => sum + d.count, 0);
101
- injections = { total, by_day: byDay };
102
- } catch (err) {
103
- console.log('[ActivitySummary] Injections query failed:', err.message);
104
- }
105
-
106
- // Promotions: standard_promoted events + current state counts
107
- let promotions = { total: 0, by_state: { proposed: 0, active: 0 } };
108
- try {
109
- const promotionResult = await executeQuery(`
110
- SELECT COUNT(*) as count
111
- FROM rapport.audit_trail at
112
- JOIN rapport.user_entitlements ue ON at.email_address = ue.email_address
113
- WHERE ue.company_id = $1
114
- AND at.action = 'standard_promoted'
115
- AND at.created_at >= $2
116
- ${projectFilter}
117
- `, baseParams);
118
-
119
- const total = parseInt(promotionResult.rows[0].count, 10) || 0;
120
-
121
- // Get current state breakdown
122
- const stateResult = await executeQuery(`
123
- SELECT
124
- p.status,
125
- COUNT(*) as count
126
- FROM rapport.patterns p
127
- JOIN rapport.user_entitlements ue ON p.created_by = ue.email_address
128
- WHERE ue.company_id = $1
129
- AND p.status IN ('proposed', 'active')
130
- ${projectId ? 'AND p.project_id = $3' : ''}
131
- GROUP BY p.status
132
- `, baseParams);
133
-
134
- const byState = { proposed: 0, active: 0 };
135
- for (const row of stateResult.rows) {
136
- if (row.status === 'proposed') byState.proposed = parseInt(row.count, 10);
137
- if (row.status === 'active') byState.active = parseInt(row.count, 10);
138
- }
139
-
140
- promotions = { total, by_state: byState };
141
- } catch (err) {
142
- console.log('[ActivitySummary] Promotions query failed:', err.message);
143
- }
144
-
145
- // Violations: violation_detected events by category
146
- let violations = { total: 0, by_category: [] };
147
- try {
148
- const violationResult = await executeQuery(`
149
- SELECT
150
- COALESCE(at.details->>'category', 'uncategorized') as category,
151
- COUNT(*) as count
152
- FROM rapport.audit_trail at
153
- JOIN rapport.user_entitlements ue ON at.email_address = ue.email_address
154
- WHERE ue.company_id = $1
155
- AND at.action = 'violation_detected'
156
- AND at.created_at >= $2
157
- ${projectFilter}
158
- GROUP BY COALESCE(at.details->>'category', 'uncategorized')
159
- ORDER BY count DESC
160
- `, baseParams);
161
-
162
- const byCategory = violationResult.rows.map(row => ({
163
- category: row.category,
164
- count: parseInt(row.count, 10)
165
- }));
166
- const total = byCategory.reduce((sum, c) => sum + c.count, 0);
167
- violations = { total, by_category: byCategory };
168
- } catch (err) {
169
- console.log('[ActivitySummary] Violations query failed:', err.message);
170
- }
171
-
172
- // Top standards by usage count from session_standards
173
- let topStandards = [];
174
- try {
175
- const standardsResult = await executeQuery(`
176
- SELECT
177
- ss.standard_name,
178
- COUNT(*) as count
179
- FROM rapport.session_standards ss
180
- JOIN rapport.sessions s ON s.session_id = ss.session_id
181
- JOIN rapport.user_entitlements ue ON s.email_address = ue.email_address
182
- WHERE ue.company_id = $1
183
- AND ss.created_at >= $2
184
- ${projectId ? 'AND s.project_id = $3' : ''}
185
- GROUP BY ss.standard_name
186
- ORDER BY count DESC
187
- LIMIT 10
188
- `, baseParams);
189
-
190
- topStandards = standardsResult.rows.map(row => ({
191
- standard_name: row.standard_name,
192
- count: parseInt(row.count, 10)
193
- }));
194
- } catch (err) {
195
- console.log('[ActivitySummary] Top standards query failed:', err.message);
196
- }
197
-
198
- return createSuccessResponse(
199
- {
200
- period,
201
- period_days: periodDays,
202
- period_start: periodStart.toISOString(),
203
- period_end: new Date().toISOString(),
204
- harvests,
205
- injections,
206
- promotions,
207
- violations,
208
- top_standards: topStandards
209
- },
210
- 'Activity summary retrieved',
211
- { Request_ID, Timestamp: new Date().toISOString() }
212
- );
213
- }
214
-
215
- exports.handler = wrapHandler(getActivitySummary);
216
-
217
- /**
218
- * Parse period string into number of days
219
- * @param {string} period - Period string (7d, 30d, 90d)
220
- * @returns {number} Number of days
221
- */
222
- function parsePeriod(period) {
223
- const match = period.match(/^(\d+)([d])$/);
224
- if (!match) return 7;
225
-
226
- const [, num] = match;
227
- const days = parseInt(num, 10);
228
-
229
- // Cap at 90 days
230
- if (days > 90) return 90;
231
- if (days < 1) return 7;
232
-
233
- return days;
234
- }