@equilateral_ai/mindmeld 3.3.1 → 3.5.0

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 (72) hide show
  1. package/README.md +1 -10
  2. package/hooks/pre-compact.js +213 -25
  3. package/hooks/session-end.js +112 -3
  4. package/hooks/session-start.js +635 -41
  5. package/hooks/subagent-start.js +150 -0
  6. package/hooks/subagent-stop.js +184 -0
  7. package/package.json +8 -7
  8. package/scripts/init-project.js +74 -33
  9. package/scripts/mcp-bridge.js +220 -0
  10. package/src/core/CorrelationAnalyzer.js +157 -0
  11. package/src/core/LLMPatternDetector.js +198 -0
  12. package/src/core/RelevanceDetector.js +123 -36
  13. package/src/core/StandardsIngestion.js +119 -18
  14. package/src/handlers/activity/activityGetMe.js +1 -1
  15. package/src/handlers/activity/activityGetTeam.js +100 -55
  16. package/src/handlers/admin/adminSetup.js +216 -0
  17. package/src/handlers/alerts/alertsAcknowledge.js +6 -6
  18. package/src/handlers/alerts/alertsGet.js +11 -11
  19. package/src/handlers/analytics/activitySummaryGet.js +34 -35
  20. package/src/handlers/analytics/coachingGet.js +11 -11
  21. package/src/handlers/analytics/convergenceGet.js +236 -0
  22. package/src/handlers/analytics/developerScoreGet.js +41 -111
  23. package/src/handlers/collaborators/collaboratorInvite.js +1 -1
  24. package/src/handlers/company/companyUsersDelete.js +141 -0
  25. package/src/handlers/company/companyUsersGet.js +90 -0
  26. package/src/handlers/company/companyUsersPost.js +267 -0
  27. package/src/handlers/company/companyUsersPut.js +76 -0
  28. package/src/handlers/correlations/correlationsDeveloperGet.js +12 -12
  29. package/src/handlers/correlations/correlationsGet.js +8 -8
  30. package/src/handlers/correlations/correlationsProjectGet.js +5 -5
  31. package/src/handlers/enterprise/controlTowerGet.js +224 -0
  32. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +48 -9
  33. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +1 -3
  34. package/src/handlers/github/githubConnectionStatus.js +1 -1
  35. package/src/handlers/github/githubDiscoverPatterns.js +4 -2
  36. package/src/handlers/github/githubPatternsReview.js +7 -36
  37. package/src/handlers/health/healthGet.js +55 -0
  38. package/src/handlers/helpers/checkSuperAdmin.js +13 -14
  39. package/src/handlers/helpers/mindmeldMcpCore.js +594 -0
  40. package/src/handlers/helpers/subscriptionTiers.js +27 -27
  41. package/src/handlers/mcp/mcpHandler.js +569 -0
  42. package/src/handlers/mcp/mindmeldMcpHandler.js +124 -0
  43. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +243 -0
  44. package/src/handlers/notifications/sendNotification.js +18 -18
  45. package/src/handlers/patterns/patternEvaluatePromotionPost.js +173 -0
  46. package/src/handlers/projects/projectCreate.js +124 -10
  47. package/src/handlers/projects/projectDelete.js +4 -4
  48. package/src/handlers/projects/projectGet.js +8 -8
  49. package/src/handlers/projects/projectUpdate.js +4 -4
  50. package/src/handlers/reports/aiLeverage.js +34 -30
  51. package/src/handlers/reports/engineeringInvestment.js +16 -16
  52. package/src/handlers/reports/riskForecast.js +41 -21
  53. package/src/handlers/reports/standardsRoi.js +101 -9
  54. package/src/handlers/scheduled/maturityUpdateJob.js +166 -0
  55. package/src/handlers/sessions/sessionStandardsPost.js +43 -7
  56. package/src/handlers/standards/discoveriesGet.js +93 -0
  57. package/src/handlers/standards/projectStandardsGet.js +2 -2
  58. package/src/handlers/standards/projectStandardsPut.js +2 -2
  59. package/src/handlers/standards/standardsRelevantPost.js +107 -12
  60. package/src/handlers/standards/standardsTransition.js +112 -15
  61. package/src/handlers/stripe/billingPortalPost.js +1 -1
  62. package/src/handlers/stripe/enterpriseCheckoutPost.js +2 -2
  63. package/src/handlers/stripe/subscriptionCreatePost.js +2 -2
  64. package/src/handlers/stripe/webhookPost.js +42 -14
  65. package/src/handlers/user/apiTokenCreate.js +71 -0
  66. package/src/handlers/user/apiTokenList.js +64 -0
  67. package/src/handlers/user/userSplashGet.js +90 -73
  68. package/src/handlers/users/cognitoPostConfirmation.js +37 -1
  69. package/src/handlers/users/cognitoPreSignUp.js +114 -0
  70. package/src/handlers/users/userGet.js +15 -11
  71. package/src/handlers/webhooks/githubWebhook.js +117 -125
  72. package/src/index.js +8 -5
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Admin Setup Handler
3
+ * One-time setup for enterprise clients via Lambda invocation
4
+ *
5
+ * Invoke via AWS CLI:
6
+ * aws lambda invoke --function-name rapport-api-prod-AdminSetup \
7
+ * --payload '{"action":"setup-equilateral"}' \
8
+ * --profile production-sso response.json
9
+ */
10
+
11
+ const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('../helpers');
12
+
13
+ const SETUP_CONFIGS = {
14
+ 'setup-equilateral': {
15
+ client: {
16
+ client_id: 'EQUILATERAL_MAIN',
17
+ client_name: 'Equilateral AI',
18
+ client_type: 'ENTERPRISE',
19
+ subscription_tier: 'enterprise',
20
+ seat_count: 25,
21
+ billing_type: 'internal'
22
+ },
23
+ company: {
24
+ company_id: 'EQUILATERAL_MAIN',
25
+ company_name: 'Equilateral AI'
26
+ },
27
+ admin_email: 'james.ford@happyhippo.ai',
28
+ invitations: [
29
+ { email: 'adeel@equilateral.ai', name: 'Adeel', role: 'member' },
30
+ { email: 'satish@equilateral.ai', name: 'Satish', role: 'member' }
31
+ ]
32
+ }
33
+ };
34
+
35
+ async function adminSetup({ body }) {
36
+ try {
37
+ const action = body?.action;
38
+
39
+ // Special action: list-tables
40
+ if (action === 'list-tables') {
41
+ const result = await executeQuery(`
42
+ SELECT table_name
43
+ FROM information_schema.tables
44
+ WHERE table_schema = 'rapport'
45
+ ORDER BY table_name
46
+ `);
47
+ return createSuccessResponse({
48
+ tables: result.rows.map(r => r.table_name)
49
+ }, `Found ${result.rows.length} tables`);
50
+ }
51
+
52
+ // Special action: run-sql (for migrations)
53
+ if (action === 'run-sql') {
54
+ const sql = body?.sql;
55
+ if (!sql) {
56
+ return createErrorResponse(400, 'sql parameter required');
57
+ }
58
+ try {
59
+ await executeQuery(sql);
60
+ return createSuccessResponse({ executed: true }, 'SQL executed successfully');
61
+ } catch (err) {
62
+ return createErrorResponse(500, `SQL error: ${err.message}`);
63
+ }
64
+ }
65
+
66
+ // Special action: query (returns results)
67
+ if (action === 'query') {
68
+ const sql = body?.sql;
69
+ if (!sql) {
70
+ return createErrorResponse(400, 'sql parameter required');
71
+ }
72
+ try {
73
+ const result = await executeQuery(sql);
74
+ return createSuccessResponse({ rows: result.rows, rowCount: result.rowCount }, `Query returned ${result.rowCount} rows`);
75
+ } catch (err) {
76
+ return createErrorResponse(500, `Query error: ${err.message}`);
77
+ }
78
+ }
79
+
80
+ if (!action || !SETUP_CONFIGS[action]) {
81
+ return createErrorResponse(400, `Invalid action. Available: ${Object.keys(SETUP_CONFIGS).join(', ')}, list-tables, run-sql`);
82
+ }
83
+
84
+ const config = SETUP_CONFIGS[action];
85
+ const results = [];
86
+
87
+ // 1. Create client
88
+ const existingClient = await executeQuery(
89
+ 'SELECT client_id FROM rapport.clients WHERE client_id = $1',
90
+ [config.client.client_id]
91
+ );
92
+
93
+ if (existingClient.rows.length > 0) {
94
+ results.push({ step: 'client', status: 'exists', client_id: config.client.client_id });
95
+ } else {
96
+ await executeQuery(`
97
+ INSERT INTO rapport.clients (
98
+ client_id, client_name, client_type, client_status, active,
99
+ subscription_tier, subscription_status, billing_type, seat_count
100
+ )
101
+ VALUES ($1, $2, $3, 'Active', true, $4, 'active', $5, $6)
102
+ `, [
103
+ config.client.client_id,
104
+ config.client.client_name,
105
+ config.client.client_type,
106
+ config.client.subscription_tier,
107
+ config.client.billing_type,
108
+ config.client.seat_count
109
+ ]);
110
+ results.push({ step: 'client', status: 'created', client_id: config.client.client_id });
111
+ }
112
+
113
+ // 2. Create company
114
+ const existingCompany = await executeQuery(
115
+ 'SELECT company_id FROM rapport.companies WHERE company_id = $1',
116
+ [config.company.company_id]
117
+ );
118
+
119
+ if (existingCompany.rows.length > 0) {
120
+ results.push({ step: 'company', status: 'exists', company_id: config.company.company_id });
121
+ } else {
122
+ await executeQuery(`
123
+ INSERT INTO rapport.companies (
124
+ company_id, client_id, company_name, company_status
125
+ )
126
+ VALUES ($1, $2, $3, 'Active')
127
+ `, [config.company.company_id, config.client.client_id, config.company.company_name]);
128
+ results.push({ step: 'company', status: 'created', company_id: config.company.company_id });
129
+ }
130
+
131
+ // 3. Create admin entitlement
132
+ const existingEntitlement = await executeQuery(
133
+ 'SELECT * FROM rapport.user_entitlements WHERE email_address = $1 AND company_id = $2',
134
+ [config.admin_email, config.company.company_id]
135
+ );
136
+
137
+ if (existingEntitlement.rows.length > 0) {
138
+ results.push({ step: 'admin_entitlement', status: 'exists', email: config.admin_email });
139
+ } else {
140
+ await executeQuery(`
141
+ INSERT INTO rapport.user_entitlements (
142
+ email_address, client_id, company_id, admin, member
143
+ )
144
+ VALUES ($1, $2, $3, true, true)
145
+ `, [config.admin_email, config.client.client_id, config.company.company_id]);
146
+ results.push({ step: 'admin_entitlement', status: 'created', email: config.admin_email });
147
+ }
148
+
149
+ // 4. Create invitations (skip if table doesn't exist)
150
+ let invitationsSkipped = false;
151
+ for (const inv of config.invitations) {
152
+ if (invitationsSkipped) {
153
+ results.push({ step: 'invitation', status: 'skipped', email: inv.email, reason: 'table not found' });
154
+ continue;
155
+ }
156
+ try {
157
+ await executeQuery(`
158
+ INSERT INTO rapport.enterprise_invitations
159
+ (client_id, company_id, email, role, invited_by, status, created_at)
160
+ VALUES ($1, $2, $3, $4, $5, 'pending', NOW())
161
+ ON CONFLICT (company_id, email) DO UPDATE SET
162
+ role = EXCLUDED.role,
163
+ invited_by = EXCLUDED.invited_by,
164
+ status = 'pending',
165
+ created_at = NOW()
166
+ `, [config.client.client_id, config.company.company_id, inv.email.toLowerCase(), inv.role, config.admin_email]);
167
+ results.push({ step: 'invitation', status: 'created', email: inv.email, role: inv.role });
168
+ } catch (err) {
169
+ if (err.code === '42P01') { // relation does not exist
170
+ invitationsSkipped = true;
171
+ results.push({ step: 'invitation', status: 'skipped', email: inv.email, reason: 'enterprise_invitations table not found' });
172
+ } else {
173
+ results.push({ step: 'invitation', status: 'error', email: inv.email, error: err.message });
174
+ }
175
+ }
176
+ }
177
+
178
+ // 5. Get final state
179
+ const clientInfo = await executeQuery(
180
+ 'SELECT client_id, client_name, subscription_tier, seat_count FROM rapport.clients WHERE client_id = $1',
181
+ [config.client.client_id]
182
+ );
183
+
184
+ const entitlements = await executeQuery(
185
+ 'SELECT email_address, admin, member FROM rapport.user_entitlements WHERE company_id = $1',
186
+ [config.company.company_id]
187
+ );
188
+
189
+ let invitationsList = [];
190
+ try {
191
+ const invitations = await executeQuery(
192
+ 'SELECT email, role, status FROM rapport.enterprise_invitations WHERE company_id = $1',
193
+ [config.company.company_id]
194
+ );
195
+ invitationsList = invitations.rows;
196
+ } catch (err) {
197
+ if (err.code !== '42P01') throw err; // rethrow if not "relation does not exist"
198
+ }
199
+
200
+ return createSuccessResponse({
201
+ action,
202
+ results,
203
+ final_state: {
204
+ client: clientInfo.rows[0],
205
+ entitlements: entitlements.rows,
206
+ invitations: invitationsList
207
+ }
208
+ }, 'Setup complete');
209
+
210
+ } catch (error) {
211
+ console.error('Admin setup error:', error);
212
+ return handleError(error);
213
+ }
214
+ }
215
+
216
+ exports.handler = wrapHandler(adminSetup);
@@ -24,10 +24,10 @@ exports.handler = wrapHandler(async ({ requestContext, body }) => {
24
24
 
25
25
  // Check user role
26
26
  const userCheck = await executeQuery(`
27
- SELECT ue."Company_ID", ue."Manager", ue."Admin", u."Super_Admin"
28
- FROM "UserEntitlements" ue
29
- JOIN "Users" u ON ue."Email_Address" = u."Email_Address"
30
- WHERE ue."Email_Address" = $1
27
+ SELECT ue.company_id, ue.manager, ue.admin, u.super_admin
28
+ FROM rapport.user_entitlements ue
29
+ JOIN rapport.users u ON ue.email_address = u.email_address
30
+ WHERE ue.email_address = $1
31
31
  `, [email]);
32
32
 
33
33
  if (userCheck.rowCount === 0) {
@@ -35,7 +35,7 @@ exports.handler = wrapHandler(async ({ requestContext, body }) => {
35
35
  }
36
36
 
37
37
  const userRole = userCheck.rows[0];
38
- const isManager = userRole.Manager || userRole.Admin || userRole.Super_Admin;
38
+ const isManager = userRole.manager || userRole.admin || userRole.super_admin;
39
39
 
40
40
  if (!isManager) {
41
41
  return createErrorResponse(403, 'Manager or Admin access required');
@@ -55,7 +55,7 @@ exports.handler = wrapHandler(async ({ requestContext, body }) => {
55
55
  }
56
56
 
57
57
  const alert = alertCheck.rows[0];
58
- if (alert.company_id !== userRole.Company_ID && !userRole.Super_Admin) {
58
+ if (alert.company_id !== userRole.company_id && !userRole.super_admin) {
59
59
  return createErrorResponse(403, 'Access denied to this alert');
60
60
  }
61
61
 
@@ -24,13 +24,13 @@ exports.handler = wrapHandler(async ({ requestContext, queryStringParameters })
24
24
  // Check user role
25
25
  const userCheck = await executeQuery(`
26
26
  SELECT
27
- ue."Company_ID",
28
- ue."Manager",
29
- ue."Admin",
30
- u."Super_Admin"
31
- FROM "UserEntitlements" ue
32
- JOIN "Users" u ON ue."Email_Address" = u."Email_Address"
33
- WHERE ue."Email_Address" = $1
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
34
  `, [email]);
35
35
 
36
36
  if (userCheck.rowCount === 0) {
@@ -38,8 +38,8 @@ exports.handler = wrapHandler(async ({ requestContext, queryStringParameters })
38
38
  }
39
39
 
40
40
  const userRole = userCheck.rows[0];
41
- const isManager = userRole.Manager || userRole.Admin || userRole.Super_Admin;
42
- const companyId = userRole.Company_ID;
41
+ const isManager = userRole.manager || userRole.admin || userRole.super_admin;
42
+ const companyId = userRole.company_id;
43
43
 
44
44
  // Parse query parameters
45
45
  const status = queryStringParameters?.status || 'active';
@@ -54,7 +54,7 @@ exports.handler = wrapHandler(async ({ requestContext, queryStringParameters })
54
54
  SELECT
55
55
  aa.alert_id,
56
56
  aa.email_address,
57
- u."User_Display_Name" as user_name,
57
+ CONCAT(u.first_name, ' ', u.last_name) as user_name,
58
58
  aa.alert_type,
59
59
  aa.severity,
60
60
  aa.details,
@@ -64,7 +64,7 @@ exports.handler = wrapHandler(async ({ requestContext, queryStringParameters })
64
64
  aa.expires_at,
65
65
  aa.created_at
66
66
  FROM rapport.attention_alerts aa
67
- JOIN "Users" u ON aa.email_address = u."Email_Address"
67
+ JOIN rapport.users u ON aa.email_address = u.email_address
68
68
  WHERE aa.company_id = $1
69
69
  `;
70
70
 
@@ -25,9 +25,9 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
25
25
 
26
26
  // Verify user access
27
27
  const userCheck = await executeQuery(`
28
- SELECT ue."Company_ID"
29
- FROM "UserEntitlements" ue
30
- WHERE ue."Email_Address" = $1
28
+ SELECT ue.company_id
29
+ FROM rapport.user_entitlements ue
30
+ WHERE ue.email_address = $1
31
31
  LIMIT 1
32
32
  `, [email]);
33
33
 
@@ -35,7 +35,7 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
35
35
  return createErrorResponse(403, 'Access denied');
36
36
  }
37
37
 
38
- const companyId = userCheck.rows[0].Company_ID;
38
+ const companyId = userCheck.rows[0].company_id;
39
39
  const params = queryStringParameters || {};
40
40
  const projectId = params.project_id || null;
41
41
  const period = params.period || '7d';
@@ -58,8 +58,8 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
58
58
  DATE(p.created_at) as date,
59
59
  COUNT(*) as count
60
60
  FROM rapport.patterns p
61
- JOIN "UserEntitlements" ue ON p.created_by = ue."Email_Address"
62
- WHERE ue."Company_ID" = $1
61
+ JOIN rapport.user_entitlements ue ON p.created_by = ue.email_address
62
+ WHERE ue.company_id = $1
63
63
  AND p.created_at >= $2
64
64
  ${projectId ? 'AND p.project_id = $3' : ''}
65
65
  GROUP BY DATE(p.created_at)
@@ -76,20 +76,20 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
76
76
  console.log('[ActivitySummary] Harvests query failed:', err.message);
77
77
  }
78
78
 
79
- // Injections: standards_injected events from audit_trail
79
+ // Injections: count from session_standards joined through sessions
80
80
  let injections = { total: 0, by_day: [] };
81
81
  try {
82
82
  const injectionResult = await executeQuery(`
83
83
  SELECT
84
- DATE(at.created_at) as date,
84
+ DATE(ss.created_at) as date,
85
85
  COUNT(*) as count
86
- FROM rapport.audit_trail at
87
- JOIN "UserEntitlements" ue ON at.email_address = ue."Email_Address"
88
- WHERE ue."Company_ID" = $1
89
- AND at.action = 'standards_injected'
90
- AND at.created_at >= $2
91
- ${projectFilter}
92
- GROUP BY DATE(at.created_at)
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
93
  ORDER BY date
94
94
  `, baseParams);
95
95
 
@@ -109,8 +109,8 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
109
109
  const promotionResult = await executeQuery(`
110
110
  SELECT COUNT(*) as count
111
111
  FROM rapport.audit_trail at
112
- JOIN "UserEntitlements" ue ON at.email_address = ue."Email_Address"
113
- WHERE ue."Company_ID" = $1
112
+ JOIN rapport.user_entitlements ue ON at.email_address = ue.email_address
113
+ WHERE ue.company_id = $1
114
114
  AND at.action = 'standard_promoted'
115
115
  AND at.created_at >= $2
116
116
  ${projectFilter}
@@ -124,8 +124,8 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
124
124
  p.status,
125
125
  COUNT(*) as count
126
126
  FROM rapport.patterns p
127
- JOIN "UserEntitlements" ue ON p.created_by = ue."Email_Address"
128
- WHERE ue."Company_ID" = $1
127
+ JOIN rapport.user_entitlements ue ON p.created_by = ue.email_address
128
+ WHERE ue.company_id = $1
129
129
  AND p.status IN ('proposed', 'active')
130
130
  ${projectId ? 'AND p.project_id = $3' : ''}
131
131
  GROUP BY p.status
@@ -150,8 +150,8 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
150
150
  COALESCE(at.details->>'category', 'uncategorized') as category,
151
151
  COUNT(*) as count
152
152
  FROM rapport.audit_trail at
153
- JOIN "UserEntitlements" ue ON at.email_address = ue."Email_Address"
154
- WHERE ue."Company_ID" = $1
153
+ JOIN rapport.user_entitlements ue ON at.email_address = ue.email_address
154
+ WHERE ue.company_id = $1
155
155
  AND at.action = 'violation_detected'
156
156
  AND at.created_at >= $2
157
157
  ${projectFilter}
@@ -169,28 +169,27 @@ async function getActivitySummary({ requestContext, queryStringParameters }) {
169
169
  console.log('[ActivitySummary] Violations query failed:', err.message);
170
170
  }
171
171
 
172
- // Top standards by usage count
172
+ // Top standards by usage count from session_standards
173
173
  let topStandards = [];
174
174
  try {
175
175
  const standardsResult = await executeQuery(`
176
176
  SELECT
177
- at.resource_id as name,
178
- COUNT(*) as usage_count
179
- FROM rapport.audit_trail at
180
- JOIN "UserEntitlements" ue ON at.email_address = ue."Email_Address"
181
- WHERE ue."Company_ID" = $1
182
- AND at.action = 'standards_injected'
183
- AND at.created_at >= $2
184
- AND at.resource_id IS NOT NULL
185
- ${projectFilter}
186
- GROUP BY at.resource_id
187
- ORDER BY usage_count DESC
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
188
187
  LIMIT 10
189
188
  `, baseParams);
190
189
 
191
190
  topStandards = standardsResult.rows.map(row => ({
192
- name: row.name,
193
- usage_count: parseInt(row.usage_count, 10)
191
+ standard_name: row.standard_name,
192
+ count: parseInt(row.count, 10)
194
193
  }));
195
194
  } catch (err) {
196
195
  console.log('[ActivitySummary] Top standards query failed:', err.message);
@@ -43,12 +43,12 @@ async function getCoachingRecommendations({ requestContext, queryStringParameter
43
43
 
44
44
  if (!isSelf) {
45
45
  const accessCheck = await executeQuery(`
46
- SELECT ue."Company_ID"
47
- FROM "UserEntitlements" ue
48
- JOIN rapport.projects p ON p."Company_ID" = ue."Company_ID"
49
- WHERE ue."Email_Address" = $1
46
+ SELECT ue.company_id
47
+ FROM rapport.user_entitlements ue
48
+ JOIN rapport.projects p ON p.company_id = ue.company_id
49
+ WHERE ue.email_address = $1
50
50
  AND p.project_id = $2
51
- AND (ue."Admin" = true OR ue."Manager" = true)
51
+ AND (ue.admin = true OR ue.manager = true)
52
52
  LIMIT 1
53
53
  `, [email, projectId]);
54
54
 
@@ -60,12 +60,12 @@ async function getCoachingRecommendations({ requestContext, queryStringParameter
60
60
  // Verify target user exists and belongs to the project's company
61
61
  const userResult = await executeQuery(`
62
62
  SELECT
63
- u."Email_Address" as user_email,
64
- u."User_Display_Name" as display_name
65
- FROM "Users" u
66
- JOIN "UserEntitlements" ue ON ue."Email_Address" = u."Email_Address"
67
- JOIN rapport.projects p ON p."Company_ID" = ue."Company_ID"
68
- WHERE u."Email_Address" = $1
63
+ u.email_address as user_email,
64
+ CONCAT(u.first_name, ' ', u.last_name) as display_name
65
+ FROM rapport.users u
66
+ JOIN rapport.user_entitlements ue ON ue.email_address = u.email_address
67
+ JOIN rapport.projects p ON p.company_id = ue.company_id
68
+ WHERE u.email_address = $1
69
69
  AND p.project_id = $2
70
70
  LIMIT 1
71
71
  `, [targetUserId, projectId]);