everydaycats commited on
Commit
2ecc8d1
·
verified ·
1 Parent(s): e91478b

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +54 -7
app.js CHANGED
@@ -29,7 +29,11 @@ app.post('/internal/notify', (req, res) => {
29
  const { user_id, type, message } = req.body;
30
  if (clients.has(user_id)) {
31
  clients.get(user_id).forEach(ws => {
32
- if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type, message }));
 
 
 
 
33
  });
34
  return res.json({ success: true });
35
  }
@@ -104,7 +108,7 @@ app.get('/api/projects', async (req, res) => {
104
  });
105
  });
106
 
107
- // --- NEW: FETCH ACTIVE THRUST & TASKS ---
108
  app.get('/api/projects/:projectId/thrusts/active', async (req, res) => {
109
  const authHeader = req.headers.authorization;
110
  if (!authHeader?.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
@@ -115,7 +119,6 @@ app.get('/api/projects/:projectId/thrusts/active', async (req, res) => {
115
 
116
  const { projectId } = req.params;
117
 
118
- // Fetch the thrust AND join its associated tasks
119
  const { data, error } = await supabase
120
  .from('thrusts')
121
  .select('*, thrust_tasks(*)')
@@ -125,12 +128,46 @@ app.get('/api/projects/:projectId/thrusts/active', async (req, res) => {
125
  .limit(1);
126
 
127
  if (error) return res.status(500).json({ error: error.message });
128
-
129
- // Order tasks by creation ID/time if needed, but Supabase usually returns them in insert order.
130
  res.json(data);
131
  });
132
 
133
- // --- NEW: MARK TASK COMPLETE & LOG TO TIMELINE ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  app.post('/api/projects/:projectId/tasks/:taskId/complete', async (req, res) => {
135
  const authHeader = req.headers.authorization;
136
  if (!authHeader?.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
@@ -146,7 +183,7 @@ app.post('/api/projects/:projectId/tasks/:taskId/complete', async (req, res) =>
146
  // 1. Update Task Status
147
  const { error: updateError } = await supabase
148
  .from('thrust_tasks')
149
- .update({ is_completed: true })
150
  .eq('id', taskId);
151
 
152
  if (updateError) throw updateError;
@@ -163,6 +200,16 @@ app.post('/api/projects/:projectId/tasks/:taskId/complete', async (req, res) =>
163
 
164
  if (timelineError) throw timelineError;
165
 
 
 
 
 
 
 
 
 
 
 
166
  res.json({ success: true });
167
  } catch (error) {
168
  console.error("Task Completion Error:", error.message);
 
29
  const { user_id, type, message } = req.body;
30
  if (clients.has(user_id)) {
31
  clients.get(user_id).forEach(ws => {
32
+ if (ws.readyState === WebSocket.OPEN) {
33
+ ws.send(JSON.stringify({ type, message }));
34
+ // Ensure UI reloads on significant notifications
35
+ if (type === 'toast') ws.send(JSON.stringify({ type: 'reload_project' }));
36
+ }
37
  });
38
  return res.json({ success: true });
39
  }
 
108
  });
109
  });
110
 
111
+ // --- FETCH ACTIVE THRUST & TASKS (For backward compatibility) ---
112
  app.get('/api/projects/:projectId/thrusts/active', async (req, res) => {
113
  const authHeader = req.headers.authorization;
114
  if (!authHeader?.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
 
119
 
120
  const { projectId } = req.params;
121
 
 
122
  const { data, error } = await supabase
123
  .from('thrusts')
124
  .select('*, thrust_tasks(*)')
 
128
  .limit(1);
129
 
130
  if (error) return res.status(500).json({ error: error.message });
 
 
131
  res.json(data);
132
  });
133
 
134
+ // --- NEW: COMBINED MCP CONTEXT FETCH ---
135
+ app.get('/api/projects/:projectId/mcp-context', async (req, res) => {
136
+ const authHeader = req.headers.authorization;
137
+ if (!authHeader?.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
138
+
139
+ const token = authHeader.split(' ')[1];
140
+ const decoded = await verifyThrustToken(token);
141
+ if (!decoded || !decoded.uid) return res.status(403).json({ error: 'Invalid Token' });
142
+
143
+ const { projectId } = req.params;
144
+ const { prd, thrust, timeline } = req.query;
145
+
146
+ let result = {};
147
+
148
+ try {
149
+ if (prd === 'true') {
150
+ const { data } = await supabase.from('leads').select('requirements_doc').eq('id', projectId).single();
151
+ result.prd = data?.requirements_doc || null;
152
+ }
153
+
154
+ if (thrust === 'true') {
155
+ const { data } = await supabase.from('thrusts').select('*, tasks:thrust_tasks(*)').eq('lead_id', projectId).eq('status', 'active').order('created_at', { ascending: false }).limit(1).single();
156
+ result.thrust = data || null;
157
+ }
158
+
159
+ if (timeline === 'true') {
160
+ const { data } = await supabase.from('timeline_events').select('*').eq('lead_id', projectId).order('created_at', { ascending: false }).limit(20);
161
+ result.timeline = data || [];
162
+ }
163
+
164
+ res.json(result);
165
+ } catch (error) {
166
+ res.status(500).json({ error: error.message });
167
+ }
168
+ });
169
+
170
+ // --- MARK TASK COMPLETE & LOG TO TIMELINE ---
171
  app.post('/api/projects/:projectId/tasks/:taskId/complete', async (req, res) => {
172
  const authHeader = req.headers.authorization;
173
  if (!authHeader?.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
 
183
  // 1. Update Task Status
184
  const { error: updateError } = await supabase
185
  .from('thrust_tasks')
186
+ .update({ is_completed: true, status: 'done' })
187
  .eq('id', taskId);
188
 
189
  if (updateError) throw updateError;
 
200
 
201
  if (timelineError) throw timelineError;
202
 
203
+ // 3. Notify the local WebSockets to show a toast and reload!
204
+ if (clients.has(decoded.uid)) {
205
+ clients.get(decoded.uid).forEach(ws => {
206
+ if (ws.readyState === WebSocket.OPEN) {
207
+ ws.send(JSON.stringify({ type: 'toast', message: `✅ Task Completed: ${taskTitle || 'a task'}` }));
208
+ ws.send(JSON.stringify({ type: 'reload_project' }));
209
+ }
210
+ });
211
+ }
212
+
213
  res.json({ success: true });
214
  } catch (error) {
215
  console.error("Task Completion Error:", error.message);