File size: 10,736 Bytes
529090e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
import { Router } from 'express';
import type { Request, Response } from 'express';
import multer from 'multer';
import path from 'path';

const router = Router();

// Configure multer for file uploads
const upload = multer({
  storage: multer.memoryStorage(),
  limits: {
    fileSize: 10 * 1024 * 1024, // 10MB limit
  },
  fileFilter: (_req, file, cb) => {
    // Accept code files and documents
    const allowedExtensions = ['.js', '.ts', '.tsx', '.jsx', '.py', '.java', '.cs', '.go', '.md', '.txt', '.pdf', '.docx'];
    const ext = path.extname(file.originalname).toLowerCase();

    if (allowedExtensions.includes(ext)) {
      cb(null, true);
    } else {
      cb(new Error('Invalid file type. Allowed: ' + allowedExtensions.join(', ')));
    }
  }
});

interface Finding {
  file: string;
  line: number;
  severity: 'critical' | 'high' | 'medium' | 'low';
  category: string;
  description: string;
  remediation: string;
}

interface AnalysisResult {
  summary: {
    criticalIssues: number;
    highIssues: number;
    mediumIssues: number;
    lowIssues: number;
    totalFiles: number;
  };
  findings: Finding[];
  overallScore: number;
}

interface PersonaFeedback {
  persona: string;
  role: string;
  feedback: string;
  confidence: number;
  recommendations: string[];
  concerns: string[];
}

interface ReviewResult {
  summary: string;
  consensus: string[];
  disagreements: string[];
  personas: PersonaFeedback[];
  overallScore: number;
}

// Code Analysis Endpoint
router.post('/analyze', upload.single('file'), async (req: Request, res: Response) => {
  try {
    if (!req.file) {
      return res.status(400).json({
        error: 'No file uploaded',
        message: 'Please upload a code file for analysis'
      });
    }

    const file = req.file;
    const fileContent = file.buffer?.toString('utf-8') ?? '';
    const fileName = file.originalname;

    console.log('Code analysis requested:', {
      fileName,
      fileSize: file.size,
      mimeType: file.mimetype
    });

    // TODO: Integrate with actual code analysis service (e.g., ESLint, SonarQube, custom security scanner)
    // For now, return mock analysis results

    if (!fileContent) {
      return res.status(400).json({
        error: 'Empty file',
        message: 'Uploaded file does not contain any readable content'
      });
    }

    // Simulate finding issues based on common patterns
    const findings: Finding[] = [];
    const lines = fileContent.split('\n');

    // Mock security checks
    lines.forEach((line, index) => {
      if (line.includes('eval(') || line.includes('innerHTML')) {
        findings.push({
          file: fileName,
          line: index + 1,
          severity: 'critical',
          category: 'Security - XSS',
          description: 'Potential XSS vulnerability detected',
          remediation: 'Use secure alternatives like textContent or sanitize user input'
        });
      }

      if (line.includes('SELECT * FROM') && line.includes('+')) {
        findings.push({
          file: fileName,
          line: index + 1,
          severity: 'critical',
          category: 'Security - SQL Injection',
          description: 'Potential SQL injection vulnerability',
          remediation: 'Use parameterized queries or prepared statements'
        });
      }

      if (line.includes('console.log(')) {
        findings.push({
          file: fileName,
          line: index + 1,
          severity: 'low',
          category: 'Code Quality',
          description: 'Console.log statement found',
          remediation: 'Remove console.log or replace with proper logging'
        });
      }

      if (line.includes('any')) {
        findings.push({
          file: fileName,
          line: index + 1,
          severity: 'medium',
          category: 'Type Safety',
          description: 'Use of "any" type reduces type safety',
          remediation: 'Use specific types instead of any'
        });
      }
    });

    // Calculate summary
    const summary = {
      criticalIssues: findings.filter(f => f.severity === 'critical').length,
      highIssues: findings.filter(f => f.severity === 'high').length,
      mediumIssues: findings.filter(f => f.severity === 'medium').length,
      lowIssues: findings.filter(f => f.severity === 'low').length,
      totalFiles: 1
    };

    // Calculate overall score (0-100)
    const totalIssues = summary.criticalIssues + summary.highIssues + summary.mediumIssues + summary.lowIssues;
    const weightedScore =
      (summary.criticalIssues * 20) +
      (summary.highIssues * 10) +
      (summary.mediumIssues * 5) +
      (summary.lowIssues * 2);
    const overallScore = Math.max(0, Math.min(100, 100 - weightedScore));

    const result: AnalysisResult = {
      summary,
      findings: findings.slice(0, 20), // Limit to 20 findings
      overallScore
    };

    res.json(result);
  } catch (error) {
    console.error('Code analysis error:', error);
    res.status(500).json({
      error: 'Analysis failed',
      message: error instanceof Error ? error.message : 'Unknown error occurred'
    });
  }
});

// Spec Panel Multi-Expert Review Endpoint
router.post('/spec-panel', upload.single('file'), async (req: Request, res: Response) => {
  try {
    if (!req.file) {
      return res.status(400).json({
        error: 'No file uploaded',
        message: 'Please upload a specification document for review'
      });
    }

    const file = req.file;
    const fileContent = file.buffer.toString('utf-8');
    const fileName = file.originalname;

    // Parse personas from request
    let selectedPersonas: string[] = [];
    try {
      selectedPersonas = req.body.personas
        ? JSON.parse(req.body.personas)
        : ['architecture', 'security'];
    } catch (e) {
      selectedPersonas = ['architecture', 'security'];
    }

    console.log('Spec panel review requested:', {
      fileName,
      fileSize: file.size,
      personas: selectedPersonas
    });

    // TODO: Integrate with actual multi-expert review system (e.g., CGentCore business panel)
    // For now, return mock expert feedback

    const personaFeedbackMap: Record<string, PersonaFeedback> = {
      architecture: {
        persona: 'architecture',
        role: 'Architecture Expert',
        feedback: 'Systemdesignet viser god separation of concerns. Dog mangler der detaljer omkring skalering og fejlhåndtering ved høj belastning.',
        confidence: 0.82,
        recommendations: [
          'Implementér circuit breaker pattern til eksterne API-kald',
          'Overvej event-driven arkitektur for asynkron kommunikation',
          'Tilføj caching-lag for at reducere database-belastning'
        ],
        concerns: [
          'Manglende beskrivelse af disaster recovery strategi',
          'Uklart hvordan microservices kommunikerer ved netværksfejl'
        ]
      },
      security: {
        persona: 'security',
        role: 'Security Expert',
        feedback: 'Sikkerhedsaspekterne er overordnet acceptable, men der mangler konkrete detaljer om authentication og authorization flow.',
        confidence: 0.75,
        recommendations: [
          'Implementér OAuth 2.0 med PKCE for frontend authentication',
          'Brug JWT med kort levetid og refresh tokens',
          'Tilføj rate limiting på alle API endpoints'
        ],
        concerns: [
          'Ingen beskrivelse af encryption at rest',
          'Manglende detaljer om GDPR compliance',
          'Uklart hvordan sensitiv data håndteres i logs'
        ]
      },
      backend: {
        persona: 'backend',
        role: 'Backend Expert',
        feedback: 'API-designet følger RESTful principper godt. Performance-overvejelser skal dog specificeres mere detaljeret.',
        confidence: 0.88,
        recommendations: [
          'Implementér database connection pooling',
          'Overvej GraphQL for komplekse data-queries',
          'Tilføj API versioning fra start'
        ],
        concerns: [
          'Manglende beskrivelse af database indexing strategi',
          'Uklart hvordan N+1 query problemet undgås'
        ]
      },
      frontend: {
        persona: 'frontend',
        role: 'Frontend Expert',
        feedback: 'UI/UX-beskrivelsen er god, men der mangler detaljer om accessibility og responsive design implementering.',
        confidence: 0.79,
        recommendations: [
          'Implementér WCAG 2.1 Level AA standarder',
          'Brug progressive enhancement for bedre compatibility',
          'Tilføj offline-first capabilities med service workers'
        ],
        concerns: [
          'Ingen beskrivelse af keyboard navigation',
          'Manglende plan for internationalization (i18n)',
          'Uklart hvordan fejl præsenteres for brugeren'
        ]
      }
    };

    // Build response based on selected personas
    const personas: PersonaFeedback[] = selectedPersonas
      .filter(p => personaFeedbackMap[p])
      .map(p => personaFeedbackMap[p]);

    // Find consensus and disagreements
    const allRecommendations = personas.flatMap(p => p.recommendations);
    const allConcerns = personas.flatMap(p => p.concerns);

    const consensus = [
      'Systemet har et solidt fundament med god separation of concerns',
      'Der er behov for mere detaljering omkring fejlhåndtering og resiliens',
      'Sikkerhed og performance skal prioriteres højere i implementeringsfasen'
    ];

    const disagreements = [
      'Architecture anbefaler event-driven, mens Backend foretrækker traditionel REST',
      'Security ønsker streng authentication, Frontend ønsker friktionsløs brugeroplevelse',
      'Trade-off mellem kompleksitet og fleksibilitet i arkitekturen'
    ];

    // Calculate overall score based on confidence
    const avgConfidence = personas.reduce((sum, p) => sum + p.confidence, 0) / personas.length;
    const overallScore = Math.round(avgConfidence * 100);

    const result: ReviewResult = {
      summary: `${personas.length} eksperter har gennemgået specifikationen. Overordnet vurdering: God struktur med behov for flere tekniske detaljer.`,
      consensus,
      disagreements,
      personas,
      overallScore
    };

    res.json(result);
  } catch (error) {
    console.error('Spec panel review error:', error);
    res.status(500).json({
      error: 'Review failed',
      message: error instanceof Error ? error.message : 'Unknown error occurred'
    });
  }
});

// Health check endpoint
router.get('/health', (_req: Request, res: Response) => {
  res.json({
    status: 'ok',
    service: 'sc',
    endpoints: ['/analyze', '/spec-panel'],
    timestamp: new Date().toISOString()
  });
});

export { router as scRouter };