@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.
- package/hooks/session-end.js +25 -0
- package/hooks/session-start.js +363 -83
- package/hooks/session-watcher.js +585 -0
- package/package.json +19 -13
- package/scripts/init-project.js +9 -23
- package/src/client/dbShim.js +16 -0
- package/src/core/AuthManager.js +3 -2
- package/src/handlers/helpers/dbOperations.js +9 -46
- package/src/index.js +2 -217
- package/src/utils/piiMask.js +16 -0
- package/scripts/harvest.js +0 -601
- package/scripts/inject.js +0 -409
- package/scripts/mcp-bridge.js +0 -220
- package/scripts/repo-analyzer.js +0 -870
- package/src/collaboration/CollaborationPrompt.js +0 -460
- package/src/core/AlertEngine.js +0 -813
- package/src/core/AlertNotifier.js +0 -363
- package/src/core/CorrelationAnalyzer.js +0 -931
- package/src/core/CrossReferenceEngine.js +0 -624
- package/src/core/CurationEngine.js +0 -688
- package/src/core/DeprecationScheduler.js +0 -183
- package/src/core/LoadBearingDetector.js +0 -242
- package/src/core/NotificationService.js +0 -1032
- package/src/core/RapportOrchestrator.js +0 -632
- package/src/core/RelevanceDetector.js +0 -694
- package/src/core/StandardLifecycle.js +0 -244
- package/src/core/StandardsIngestion.js +0 -991
- package/src/core/TeamLoadBearingDetector.js +0 -431
- package/src/core/parsers/adrParser.js +0 -479
- package/src/core/parsers/cursorRulesParser.js +0 -564
- package/src/core/parsers/eslintParser.js +0 -439
- package/src/database/dbOperations.js +0 -105
- package/src/handlers/activity/activityGetMe.js +0 -98
- package/src/handlers/activity/activityGetTeam.js +0 -175
- package/src/handlers/admin/adminSetup.js +0 -216
- package/src/handlers/alerts/alertsAcknowledge.js +0 -92
- package/src/handlers/alerts/alertsGet.js +0 -250
- package/src/handlers/analytics/activitySummaryGet.js +0 -234
- package/src/handlers/analytics/coachingGet.js +0 -361
- package/src/handlers/analytics/convergenceGet.js +0 -236
- package/src/handlers/analytics/developerScoreGet.js +0 -137
- package/src/handlers/collaborators/collaboratorAdd.js +0 -200
- package/src/handlers/collaborators/collaboratorInvite.js +0 -219
- package/src/handlers/collaborators/collaboratorList.js +0 -82
- package/src/handlers/collaborators/collaboratorRemove.js +0 -128
- package/src/handlers/collaborators/inviteAccept.js +0 -122
- package/src/handlers/company/companyUsersDelete.js +0 -141
- package/src/handlers/company/companyUsersGet.js +0 -90
- package/src/handlers/company/companyUsersPost.js +0 -267
- package/src/handlers/company/companyUsersPut.js +0 -76
- package/src/handlers/context/contextGet.js +0 -57
- package/src/handlers/context/invariantsGet.js +0 -74
- package/src/handlers/context/loopsGet.js +0 -82
- package/src/handlers/context/notesCreate.js +0 -74
- package/src/handlers/context/purposeGet.js +0 -78
- package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
- package/src/handlers/correlations/correlationsGet.js +0 -93
- package/src/handlers/correlations/correlationsProjectGet.js +0 -153
- package/src/handlers/enterprise/controlTowerGet.js +0 -224
- package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
- package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
- package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
- package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
- package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
- package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
- package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
- package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
- package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
- package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
- package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
- package/src/handlers/github/githubConnectionStatus.js +0 -49
- package/src/handlers/github/githubDiscoverPatterns.js +0 -621
- package/src/handlers/github/githubOAuthCallback.js +0 -178
- package/src/handlers/github/githubOAuthStart.js +0 -59
- package/src/handlers/github/githubPatternsReview.js +0 -76
- package/src/handlers/github/githubReposList.js +0 -105
- package/src/handlers/health/healthGet.js +0 -55
- package/src/handlers/helpers/auditLogger.js +0 -201
- package/src/handlers/helpers/checkSuperAdmin.js +0 -84
- package/src/handlers/helpers/decisionFrames.js +0 -29
- package/src/handlers/helpers/errorHandler.js +0 -49
- package/src/handlers/helpers/index.js +0 -138
- package/src/handlers/helpers/lambdaWrapper.js +0 -60
- package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
- package/src/handlers/helpers/predictiveCache.js +0 -51
- package/src/handlers/helpers/projectAccess.js +0 -88
- package/src/handlers/helpers/responseUtil.js +0 -55
- package/src/handlers/helpers/subscriptionTiers.js +0 -1168
- package/src/handlers/mcp/mcpHandler.js +0 -569
- package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
- package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
- package/src/handlers/notifications/getPreferences.js +0 -84
- package/src/handlers/notifications/sendNotification.js +0 -170
- package/src/handlers/notifications/updatePreferences.js +0 -316
- package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
- package/src/handlers/patterns/patternUsagePost.js +0 -182
- package/src/handlers/patterns/patternViolationPost.js +0 -185
- package/src/handlers/projects/projectCreate.js +0 -248
- package/src/handlers/projects/projectDelete.js +0 -82
- package/src/handlers/projects/projectGet.js +0 -95
- package/src/handlers/projects/projectUpdate.js +0 -117
- package/src/handlers/reports/aiLeverage.js +0 -210
- package/src/handlers/reports/engineeringInvestment.js +0 -132
- package/src/handlers/reports/riskForecast.js +0 -206
- package/src/handlers/reports/standardsRoi.js +0 -254
- package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
- package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
- package/src/handlers/scheduled/generateAlerts.js +0 -135
- package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
- package/src/handlers/scheduled/refreshActivity.js +0 -21
- package/src/handlers/scheduled/scanCompliance.js +0 -334
- package/src/handlers/sessions/sessionEndPost.js +0 -180
- package/src/handlers/sessions/sessionStandardsPost.js +0 -171
- package/src/handlers/standards/catalogGet.js +0 -185
- package/src/handlers/standards/catalogSync.js +0 -120
- package/src/handlers/standards/discoveriesGet.js +0 -89
- package/src/handlers/standards/projectStandardsGet.js +0 -129
- package/src/handlers/standards/projectStandardsPut.js +0 -151
- package/src/handlers/standards/standardsAuditGet.js +0 -65
- package/src/handlers/standards/standardsParseUpload.js +0 -149
- package/src/handlers/standards/standardsRelevantPost.js +0 -405
- package/src/handlers/standards/standardsTransition.js +0 -161
- package/src/handlers/stripe/addonManagePost.js +0 -240
- package/src/handlers/stripe/billingPortalPost.js +0 -93
- package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
- package/src/handlers/stripe/seatsUpdatePost.js +0 -185
- package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
- package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
- package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
- package/src/handlers/stripe/webhookPost.js +0 -482
- package/src/handlers/user/apiTokenCreate.js +0 -71
- package/src/handlers/user/apiTokenList.js +0 -64
- package/src/handlers/user/userSplashAck.js +0 -91
- package/src/handlers/user/userSplashGet.js +0 -211
- package/src/handlers/users/cognitoPostConfirmation.js +0 -186
- package/src/handlers/users/cognitoPreSignUp.js +0 -114
- package/src/handlers/users/userEntitlementsGet.js +0 -89
- package/src/handlers/users/userGet.js +0 -118
- package/src/handlers/users/userProfilePut.js +0 -77
- 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
|
-
}
|