← back to kwaheedkotb__addci-prototype

Function bodies 182 total

All specs Real LLM only Function bodies
POST function · typescript · L4-L37 (34 LOC)
app/api/ai/auto-fill/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { applicationData, documents, locale = 'en' } = body

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 1200))

    const isArabic = locale === 'ar'

    // Generate suggestions based on documents and partial data
    const suggestions = generateSuggestions(applicationData, documents, isArabic)

    const hasDocuments = documents && documents.length > 0

    return NextResponse.json({
      success: true,
      suggestions,
      message: isArabic
        ? hasDocuments
          ? 'تم تحليل المستندات وإنشاء الاقتراحات بنجاح'
          : 'تم إنشاء اقتراحات بناءً على معلومات القطاع والمؤسسة'
        : hasDocuments
          ? 'Documents analyzed and suggestions generated successfully'
          : 'Suggestions generated based on sector and organization information'
    })
  } catch (error) {
    console.error('Auto-fill API error:', error)
    
generateSuggestions function · typescript · L39-L122 (84 LOC)
app/api/ai/auto-fill/route.ts
function generateSuggestions(
  applicationData: Record<string, unknown>,
  documents: Array<{ type: string; fileName: string; ocrText?: string }>,
  isArabic: boolean
) {
  // Mock suggestions - in production, this would use AI to extract from documents
  const hasPolicy = documents?.some(d =>
    d.type === 'ESG_POLICY' || d.fileName?.toLowerCase().includes('policy')
  )
  const hasReport = documents?.some(d =>
    d.type === 'REPORT' || d.fileName?.toLowerCase().includes('report')
  )
  const hasTradeLicense = documents?.some(d =>
    d.fileName?.toLowerCase().includes('license') || d.fileName?.toLowerCase().includes('trade')
  )

  const suggestions: Record<string, string> = {}

  // Only suggest values for empty fields
  if (!applicationData?.applicantName) {
    suggestions.applicantName = isArabic ? 'أحمد محمد العلي' : 'Ahmed Mohamed Al-Ali'
  }

  if (!applicationData?.organizationName) {
    suggestions.organizationName = isArabic
      ? 'شركة الحلول المستدامة ذ.م.م'
      : 
POST function · typescript · L9-L38 (30 LOC)
app/api/ai/chat/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { message, conversationHistory = [], locale = 'en' } = body

    if (!message) {
      return NextResponse.json(
        { error: 'message is required' },
        { status: 400 }
      )
    }

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 800))

    const response = generateAIResponse(message.toLowerCase(), locale, conversationHistory)

    return NextResponse.json({
      success: true,
      response,
      suggestedActions: getSuggestedActions(message.toLowerCase(), locale),
    })
  } catch (error) {
    console.error('Chat API error:', error)
    return NextResponse.json(
      { error: 'Failed to process chat message' },
      { status: 500 }
    )
  }
}
generateAIResponse function · typescript · L40-L263 (224 LOC)
app/api/ai/chat/route.ts
function generateAIResponse(message: string, locale: string, history: ChatMessage[]): string {
  const isArabic = locale === 'ar'

  // ESG Certificate related queries
  if (message.includes('esg') || message.includes('certificate') || message.includes('شهادة') || message.includes('استدامة')) {
    if (message.includes('how') || message.includes('apply') || message.includes('كيف') || message.includes('تقديم')) {
      return isArabic
        ? `للحصول على شهادة ESG، اتبع الخطوات التالية:

1. **انتقل إلى صفحة الخدمات** وابحث عن "شهادة ESG"
2. **انقر على "بدء الطلب"** لفتح نموذج الطلب
3. **أكمل الخطوات الأربع:**
   - معلومات مقدم الطلب والمؤسسة
   - ملف ESG (البيئة، الاجتماعية، الحوكمة)
   - تحميل المستندات الداعمة
   - مراجعة وإرسال الطلب

هل تريد أن أوجهك إلى صفحة تقديم الطلب؟`
        : `To obtain an ESG Certificate, follow these steps:

1. **Go to the Services page** and search for "ESG Certificate"
2. **Click "Start Application"** to open the application form
3. **Complete the 4 ste
POST function · typescript · L3-L49 (47 LOC)
app/api/ai/comment/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { description, sector, organizationName, type } = body

    // Simulate AI processing time
    await new Promise((resolve) => setTimeout(resolve, 1000))

    // type can be 'corrections', 'approval', or 'rejection'
    let comment = ''

    if (type === 'corrections') {
      const correctionComments = [
        `Thank you for your ESG certification application. After careful review, we require the following additional information before proceeding:\n\n1. Please provide specific quantitative data for your environmental impact metrics (e.g., carbon emissions in tonnes CO2e, water usage in liters, waste diversion rates).\n\n2. Include documentation or evidence supporting your sustainability claims.\n\n3. Elaborate on your governance structure and ESG oversight mechanisms.\n\n4. Add details about stakeholder engagement and reporting practices.\n\nPlease update your application with t
POST function · typescript · L4-L39 (36 LOC)
app/api/ai/compliance-score/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const {
      environmentalProfile,
      socialProfile,
      governanceProfile,
      sector,
      organizationName,
      locale = 'en'
    } = body

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 800))

    const isArabic = locale === 'ar'
    const result = calculateComplianceScore(
      environmentalProfile,
      socialProfile,
      governanceProfile,
      sector,
      isArabic
    )

    return NextResponse.json({
      success: true,
      ...result
    })
  } catch (error) {
    console.error('Compliance score API error:', error)
    return NextResponse.json(
      { error: 'Failed to calculate compliance score' },
      { status: 500 }
    )
  }
}
calculateComplianceScore function · typescript · L41-L169 (129 LOC)
app/api/ai/compliance-score/route.ts
function calculateComplianceScore(
  environmentalProfile: string | null,
  socialProfile: string | null,
  governanceProfile: string | null,
  sector: string | null,
  isArabic: boolean
) {
  let score = 0
  const hints: string[] = []
  const strengths: string[] = []

  // Parse profiles
  let envData: Record<string, string> = {}
  let socData: Record<string, string> = {}
  let govData: Record<string, string> = {}

  try {
    if (environmentalProfile) envData = JSON.parse(environmentalProfile)
    if (socialProfile) socData = JSON.parse(socialProfile)
    if (governanceProfile) govData = JSON.parse(governanceProfile)
  } catch {
    // Invalid JSON, continue with empty objects
  }

  // Environmental scoring (max 35 points)
  let envScore = 0
  if (envData.description && envData.description.length > 50) {
    envScore += 15
    strengths.push(isArabic ? 'وصف بيئي شامل' : 'Comprehensive environmental description')
  } else {
    hints.push(isArabic
      ? 'أضف وصفاً مفصلاً للمبادرات 
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
POST function · typescript · L4-L26 (23 LOC)
app/api/ai/document-classifier/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { fileName, ocrText, userSelectedType, locale = 'en', documentIndex = 0 } = body

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 600))

    const isArabic = locale === 'ar'
    const result = classifyDocument(fileName, ocrText, isArabic, documentIndex)

    return NextResponse.json({
      success: true,
      ...result
    })
  } catch (error) {
    console.error('Document classifier API error:', error)
    return NextResponse.json(
      { error: 'Failed to classify document' },
      { status: 500 }
    )
  }
}
classifyDocument function · typescript · L35-L110 (76 LOC)
app/api/ai/document-classifier/route.ts
function classifyDocument(
  fileName: string,
  ocrText: string | null,
  isArabic: boolean,
  documentIndex: number
): ClassificationResult {
  // Define document types to cycle through for demo purposes
  const documentTypes = [
    {
      type: 'ESG_POLICY',
      labelEn: 'ESG Policy',
      labelAr: 'سياسة ESG',
      confidence: 0.90,
      reasoningEn: 'Document contains organizational sustainability policies and commitments',
      reasoningAr: 'يحتوي المستند على سياسات الاستدامة والالتزامات المؤسسية'
    },
    {
      type: 'SUSTAINABILITY_REPORT',
      labelEn: 'Sustainability Report',
      labelAr: 'تقرير الاستدامة',
      confidence: 0.88,
      reasoningEn: 'Annual sustainability performance metrics and achievements identified',
      reasoningAr: 'تم تحديد مقاييس الأداء السنوية للاستدامة والإنجازات'
    },
    {
      type: 'GOVERNANCE_POLICY',
      labelEn: 'Governance Policy',
      labelAr: 'سياسة الحوكمة',
      confidence: 0.92,
      reasoningEn: 'Corporate go
POST function · typescript · L4-L31 (28 LOC)
app/api/ai/draft-certificate/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const {
      applicationData,
      complianceScore,
      locale = 'en'
    } = body

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 800))

    const isArabic = locale === 'ar'
    const certificateText = generateDraftCertificate(applicationData, complianceScore, isArabic)

    return NextResponse.json({
      success: true,
      certificateText,
      generatedAt: new Date().toISOString()
    })
  } catch (error) {
    console.error('Draft certificate API error:', error)
    return NextResponse.json(
      { error: 'Failed to generate draft certificate' },
      { status: 500 }
    )
  }
}
generateDraftCertificate function · typescript · L33-L156 (124 LOC)
app/api/ai/draft-certificate/route.ts
function generateDraftCertificate(
  applicationData: Record<string, unknown>,
  complianceScore: number | null,
  isArabic: boolean
): string {
  const orgName = applicationData?.organizationName || (isArabic ? 'المؤسسة' : 'Organization')
  const sector = applicationData?.sector || (isArabic ? 'القطاع' : 'Sector')
  const applicantName = applicationData?.applicantName || (isArabic ? 'مقدم الطلب' : 'Applicant')

  const currentDate = new Date()
  const validUntil = new Date(currentDate)
  validUntil.setFullYear(validUntil.getFullYear() + 1)

  const formatDate = (date: Date) => {
    if (isArabic) {
      return date.toLocaleDateString('ar-AE', { year: 'numeric', month: 'long', day: 'numeric' })
    }
    return date.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })
  }

  // Determine ESG level based on score
  let esgLevel: string
  if (complianceScore && complianceScore >= 80) {
    esgLevel = isArabic ? 'المستوى الذهبي' : 'Gold Level'
  } else if (comp
POST function · typescript · L4-L31 (28 LOC)
app/api/ai/draft-report/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const {
      applicationData,
      documents,
      locale = 'en'
    } = body

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 1500))

    const isArabic = locale === 'ar'
    const report = generateDraftReport(applicationData, documents, isArabic)

    return NextResponse.json({
      success: true,
      report,
      generatedAt: new Date().toISOString()
    })
  } catch (error) {
    console.error('Draft report API error:', error)
    return NextResponse.json(
      { error: 'Failed to generate draft report' },
      { status: 500 }
    )
  }
}
generateDraftReport function · typescript · L33-L191 (159 LOC)
app/api/ai/draft-report/route.ts
function generateDraftReport(
  applicationData: Record<string, unknown>,
  documents: Array<{ type: string; fileName: string }>,
  isArabic: boolean
): string {
  const orgName = applicationData?.organizationName || (isArabic ? 'المؤسسة' : 'Organization')
  const sector = applicationData?.sector || (isArabic ? 'القطاع' : 'Sector')

  // Parse ESG profiles
  let envData: Record<string, string> = {}
  let socData: Record<string, string> = {}
  let govData: Record<string, string> = {}

  try {
    if (applicationData?.environmentalProfile) {
      envData = JSON.parse(applicationData.environmentalProfile as string)
    }
    if (applicationData?.socialProfile) {
      socData = JSON.parse(applicationData.socialProfile as string)
    }
    if (applicationData?.governanceProfile) {
      govData = JSON.parse(applicationData.governanceProfile as string)
    }
  } catch {
    // Continue with empty objects
  }

  const documentTypes = documents?.map(d => d.type).join(', ') || 'N/A'

  if (is
POST function · typescript · L4-L33 (30 LOC)
app/api/ai/esg-hints/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { profile, type } = body // type: 'environmental' | 'social' | 'governance'

    if (!type) {
      return NextResponse.json(
        { error: 'type is required (environmental, social, or governance)' },
        { status: 400 }
      )
    }

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 1200))

    const hints = generateHints(type, profile)

    return NextResponse.json({
      success: true,
      type,
      hints,
    })
  } catch (error) {
    console.error('ESG Hints error:', error)
    return NextResponse.json(
      { error: 'Failed to generate ESG hints' },
      { status: 500 }
    )
  }
}
generateHints function · typescript · L35-L40 (6 LOC)
app/api/ai/esg-hints/route.ts
function generateHints(type: string, profile?: { description?: string }): {
  suggestions: string[]
  missingAreas: string[]
  improvementTips: string[]
  sampleKpis: string[]
} {
Want this analysis on your repo? https://repobility.com/scan/
POST function · typescript · L4-L200 (197 LOC)
app/api/ai/ocr-review/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { fileName, documentType } = body

    if (!fileName || !documentType) {
      return NextResponse.json(
        { error: 'fileName and documentType are required' },
        { status: 400 }
      )
    }

    // Simulate OCR processing delay
    await new Promise(resolve => setTimeout(resolve, 1500))

    // Generate mock OCR text based on document type
    const ocrTexts: Record<string, string> = {
      ESG_POLICY: `ENVIRONMENTAL, SOCIAL & GOVERNANCE POLICY

Effective Date: January 2024
Organization: [Extracted Organization Name]

1. ENVIRONMENTAL COMMITMENT
We are committed to reducing our environmental footprint through:
- Carbon neutrality targets by 2030
- 100% renewable energy usage
- Zero-waste manufacturing processes

2. SOCIAL RESPONSIBILITY
Our social initiatives include:
- Diversity and inclusion programs
- Community engagement partnerships
- Employee wellness programs
getSuggestedTags function · typescript · L202-L213 (12 LOC)
app/api/ai/ocr-review/route.ts
function getSuggestedTags(documentType: string): string[] {
  const tags: Record<string, string[]> = {
    ESG_POLICY: ['policy', 'commitment', 'strategy', 'targets'],
    SUSTAINABILITY_REPORT: ['annual-report', 'gri', 'metrics', 'disclosure'],
    CARBON_AUDIT: ['emissions', 'carbon', 'audit', 'ghg'],
    ISO_CERTIFICATE: ['iso', 'certification', 'standards', 'compliance'],
    FINANCIAL_REPORT: ['financial', 'investment', 'esg-disclosure'],
    GOVERNANCE_CHARTER: ['governance', 'board', 'committee', 'independence'],
    OTHER: ['supporting', 'documentation'],
  }
  return tags[documentType] || tags.OTHER
}
POST function · typescript · L12-L53 (42 LOC)
app/api/ai/precheck/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { description, sector, organizationName } = body

    // Simulate AI processing time
    await new Promise((resolve) => setTimeout(resolve, 1500))

    // Generate a contextual response
    let response = mockResponses[Math.floor(Math.random() * mockResponses.length)]

    // Add sector-specific suggestions
    if (sector) {
      const sectorSuggestions: Record<string, string> = {
        Energy: " For the energy sector, consider highlighting renewable energy adoption rates and grid decarbonization efforts.",
        Manufacturing: " As a manufacturing company, include details on circular economy practices and sustainable sourcing.",
        Construction: " For construction, emphasize green building certifications (LEED, BREEAM) and sustainable materials usage.",
        Agriculture: " Agricultural operations should detail organic certification status and water conservation measu
POST function · typescript · L4-L31 (28 LOC)
app/api/ai/renewal-forecast/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const {
      sector,
      organizationSize,
      complianceScore,
      locale = 'en'
    } = body

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 500))

    const isArabic = locale === 'ar'
    const forecast = calculateRenewalForecast(sector, organizationSize, complianceScore, isArabic)

    return NextResponse.json({
      success: true,
      ...forecast
    })
  } catch (error) {
    console.error('Renewal forecast API error:', error)
    return NextResponse.json(
      { error: 'Failed to calculate renewal forecast' },
      { status: 500 }
    )
  }
}
calculateRenewalForecast function · typescript · L33-L108 (76 LOC)
app/api/ai/renewal-forecast/route.ts
function calculateRenewalForecast(
  sector: string | null,
  organizationSize: string | null,
  complianceScore: number | null,
  isArabic: boolean
) {
  const now = new Date()

  // Base validity: 12 months
  let validityMonths = 12

  // Adjust based on compliance score
  if (complianceScore && complianceScore >= 85) {
    validityMonths = 18 // High performers get extended validity
  } else if (complianceScore && complianceScore < 50) {
    validityMonths = 6 // Low performers need earlier re-evaluation
  }

  // Calculate dates
  const validUntil = new Date(now)
  validUntil.setMonth(validUntil.getMonth() + validityMonths)

  const renewalSuggestedAt = new Date(validUntil)
  renewalSuggestedAt.setDate(renewalSuggestedAt.getDate() - 90) // 90 days before expiry

  const nextReviewAt = new Date(now)
  nextReviewAt.setMonth(nextReviewAt.getMonth() + Math.floor(validityMonths / 2)) // Mid-term review

  // Sector-specific recommendations
  const sectorRecommendations: Record<string, {
POST function · typescript · L5-L51 (47 LOC)
app/api/ai/reviewer-assist/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { applicationId, locale = 'en' } = body

    if (!applicationId) {
      return NextResponse.json(
        { error: 'Application ID is required' },
        { status: 400 }
      )
    }

    // Fetch application with documents
    const application = await prisma.application.findUnique({
      where: { id: applicationId },
      include: {
        documents: true,
        reviewNotes: true
      }
    })

    if (!application) {
      return NextResponse.json(
        { error: 'Application not found' },
        { status: 404 }
      )
    }

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 1000))

    const isArabic = locale === 'ar'
    const analysis = analyzeApplication(application, isArabic)

    return NextResponse.json({
      success: true,
      applicationId,
      ...analysis
    })
  } catch (error) {
    console.error('Reviewer a
analyzeApplication function · typescript · L63-L229 (167 LOC)
app/api/ai/reviewer-assist/route.ts
function analyzeApplication(
  application: {
    applicantName: string
    organizationName: string
    sector: string
    description: string
    environmentalProfile: string | null
    socialProfile: string | null
    governanceProfile: string | null
    documents: Array<{ type: string; fileName: string; ocrText: string | null }>
    reviewNotes: Array<{ note: string; authorType: string }>
  },
  isArabic: boolean
): ReviewerAnalysis {
  const redFlags: string[] = []
  const strengths: string[] = []
  const extraDocumentsSuggested: string[] = []

  // Parse ESG profiles
  let envData: Record<string, string> = {}
  let socData: Record<string, string> = {}
  let govData: Record<string, string> = {}

  try {
    if (application.environmentalProfile) {
      envData = JSON.parse(application.environmentalProfile)
    }
    if (application.socialProfile) {
      socData = JSON.parse(application.socialProfile)
    }
    if (application.governanceProfile) {
      govData = JSON.parse(applic
generateDetailedNotes function · typescript · L231-L270 (40 LOC)
app/api/ai/reviewer-assist/route.ts
function generateDetailedNotes(
  application: { organizationName: string; sector: string },
  redFlags: string[],
  strengths: string[],
  isArabic: boolean
): string {
  if (isArabic) {
    return `
## ملخص تحليل الطلب

**المؤسسة:** ${application.organizationName}
**القطاع:** ${application.sector}

### نقاط القوة (${strengths.length})
${strengths.map(s => `• ${s}`).join('\n') || '• لم يتم تحديد نقاط قوة محددة'}

### المخاوف (${redFlags.length})
${redFlags.map(r => `• ${r}`).join('\n') || '• لم يتم تحديد مخاوف'}

### ملاحظات المراجع
يرجى مراجعة الطلب بعناية والتحقق من جميع المستندات المقدمة. تأكد من أن جميع مؤشرات الأداء الرئيسية قابلة للقياس والتحقق منها.
    `.trim()
  }

  return `
## Application Analysis Summary

**Organization:** ${application.organizationName}
**Sector:** ${application.sector}

### Strengths (${strengths.length})
${strengths.map(s => `• ${s}`).join('\n') || '• No specific strengths identified'}

### Concerns (${redFlags.length})
${redFlags.map(r => `• ${r}`).joi
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
POST function · typescript · L4-L34 (31 LOC)
app/api/ai/sector-template/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { sector, locale = 'en' } = body

    if (!sector) {
      return NextResponse.json(
        { error: 'Sector is required' },
        { status: 400 }
      )
    }

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 400))

    const isArabic = locale === 'ar'
    const template = getSectorTemplate(sector, isArabic)

    return NextResponse.json({
      success: true,
      sector,
      ...template
    })
  } catch (error) {
    console.error('Sector template API error:', error)
    return NextResponse.json(
      { error: 'Failed to fetch sector template' },
      { status: 500 }
    )
  }
}
getSectorTemplate function · typescript · L46-L303 (258 LOC)
app/api/ai/sector-template/route.ts
function getSectorTemplate(sector: string, isArabic: boolean): SectorTemplate {
  const templates: Record<string, { en: SectorTemplate; ar: SectorTemplate }> = {
    'Manufacturing': {
      en: {
        environmentalTemplate: 'For manufacturing, focus on emissions reduction, waste management, and resource efficiency. Key areas include energy consumption per unit, water usage optimization, and circular economy practices.',
        environmentalExamples: [
          'Reduce carbon emissions by 25% through energy-efficient machinery',
          'Implement zero-waste-to-landfill program',
          'Use 50% recycled materials in production',
          'Install solar panels for 30% of energy needs'
        ],
        socialTemplate: 'Manufacturing social responsibility centers on worker safety, fair labor practices, and community impact. Focus on workplace conditions and supply chain ethics.',
        socialExamples: [
          'Achieve zero workplace injuries through safety training',
 
matchServices function · typescript · L20-L118 (99 LOC)
app/api/ai/service-match/route.ts
function matchServices(
  query: string,
  services: Array<{
    id: number
    name: string
    nameAr: string
    description: string
    descriptionAr: string
    tags: string | null
    tagsAr: string | null
  }>,
  lang: 'en' | 'ar'
): MatchedService[] {
  const queryLower = query.toLowerCase()
  const queryWords = queryLower.split(/\s+/).filter(w => w.length > 2)

  const scores: Array<{ serviceId: number; score: number }> = []

  for (const service of services) {
    let score = 0
    const name = lang === 'ar' ? service.nameAr : service.name
    const description = lang === 'ar' ? service.descriptionAr : service.description
    const tagsStr = lang === 'ar' ? service.tagsAr : service.tags

    const nameLower = name.toLowerCase()
    const descLower = description.toLowerCase()

    // Parse tags
    let tags: string[] = []
    if (tagsStr) {
      try {
        tags = JSON.parse(tagsStr)
      } catch {
        tags = []
      }
    }

    // Exact name match (high score)
    i
generateReasoningSummary function · typescript · L121-L137 (17 LOC)
app/api/ai/service-match/route.ts
function generateReasoningSummary(
  query: string,
  matchedCount: number,
  lang: 'en' | 'ar'
): string {
  if (lang === 'ar') {
    if (matchedCount === 0) {
      return `لم أتمكن من العثور على خدمات تتطابق مع "${query}". يرجى المحاولة بكلمات مختلفة أو تصفح دليل الخدمات.`
    }
    return `بناءً على استفسارك "${query}"، قمت بتحليل الكلمات الرئيسية والسياق لتحديد الخدمات الأكثر صلة. وجدت ${matchedCount} خدمة/خدمات قد تلبي احتياجاتك. يتم ترتيب النتائج حسب درجة الثقة بناءً على مدى تطابقها مع طلبك.`
  }

  if (matchedCount === 0) {
    return `I couldn't find any services matching "${query}". Please try different keywords or browse the service directory.`
  }
  return `Based on your query "${query}", I analyzed the keywords and context to identify the most relevant services. I found ${matchedCount} service(s) that may meet your needs. Results are ranked by confidence score based on how closely they match your request.`
}
POST function · typescript · L139-L181 (43 LOC)
app/api/ai/service-match/route.ts
export async function POST(request: NextRequest) {
  try {
    const body: ServiceMatchRequest = await request.json()
    const { query, lang = 'en' } = body

    if (!query || query.trim().length === 0) {
      return NextResponse.json(
        { error: 'Query is required' },
        { status: 400 }
      )
    }

    // Fetch all services
    const services = await prisma.service.findMany({
      select: {
        id: true,
        name: true,
        nameAr: true,
        description: true,
        descriptionAr: true,
        tags: true,
        tagsAr: true,
      },
    })

    // Match services
    const matchedServices = matchServices(query, services, lang)

    // Generate response
    const response: ServiceMatchResponse = {
      reasoningSummary: generateReasoningSummary(query, matchedServices.length, lang),
      matchedServices,
    }

    return NextResponse.json(response)
  } catch (error) {
    console.error('Service match error:', error)
    return NextResponse.json(
POST function · typescript · L5-L46 (42 LOC)
app/api/ai/service-recommendations/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const {
      sector,
      organizationSize,
      hasCompletedESG,
      locale = 'en'
    } = body

    // Simulate AI processing delay
    await new Promise(resolve => setTimeout(resolve, 600))

    const isArabic = locale === 'ar'

    // Get all services from database
    const allServices = await prisma.service.findMany()

    // Generate recommendations based on context
    const recommendations = generateRecommendations(
      allServices,
      sector,
      organizationSize,
      hasCompletedESG,
      isArabic
    )

    return NextResponse.json({
      success: true,
      recommendations,
      reasoning: isArabic
        ? 'بناءً على قطاعك وحجم مؤسستك، نوصي بالخدمات التالية'
        : 'Based on your sector and organization profile, we recommend these services'
    })
  } catch (error) {
    console.error('Service recommendations API error:', error)
    return NextRespons
generateRecommendations function · typescript · L60-L184 (125 LOC)
app/api/ai/service-recommendations/route.ts
function generateRecommendations(
  services: Array<{
    id: number
    name: string
    nameAr: string
    description: string
    descriptionAr: string
    platform: string
    dept: string
    channelType: string
    tags: string | null
  }>,
  sector: string | null,
  organizationSize: string | null,
  hasCompletedESG: boolean,
  isArabic: boolean
): ServiceRecommendation[] {
  const recommendations: ServiceRecommendation[] = []

  // Define recommendation rules
  const recommendationRules = [
    {
      namePattern: /certificate.*origin/i,
      reason: 'Essential for international trade and export activities',
      reasonAr: 'ضروري للتجارة الدولية وأنشطة التصدير',
      relevance: 85,
      sectors: ['Manufacturing', 'Trade', 'Logistics']
    },
    {
      namePattern: /business.*matchmaking/i,
      reason: 'Connect with potential partners and investors in your sector',
      reasonAr: 'تواصل مع شركاء ومستثمرين محتملين في قطاعك',
      relevance: 80,
      sectors: null // A
POST function · typescript · L3-L47 (45 LOC)
app/api/ai/summary/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { description, sector, organizationName, applicantName } = body

    // Simulate AI processing time
    await new Promise((resolve) => setTimeout(resolve, 2000))

    const riskLevel = Math.random() > 0.7 ? 'HIGH' : Math.random() > 0.4 ? 'MEDIUM' : 'LOW'
    const completenessScore = Math.floor(Math.random() * 30) + 70 // 70-100

    // Generate summary based on input
    const summaries = [
      `**Application Summary for ${organizationName}**\n\nThis application from ${applicantName} in the ${sector} sector demonstrates a commitment to ESG principles. The organization has outlined various sustainability initiatives with measurable targets.\n\n**Key Strengths:**\n- Clear environmental objectives\n- Documented social responsibility programs\n- Established governance framework\n\n**Areas for Improvement:**\n- More specific quantitative metrics needed\n- Long-term sustainability ro
All rows scored by the Repobility analyzer (https://repobility.com)
POST function · typescript · L4-L29 (26 LOC)
app/api/applications/[id]/notes/route.ts
export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params
    const body = await request.json()
    const { note, authorType = 'STAFF' } = body

    const reviewNote = await prisma.reviewNote.create({
      data: {
        applicationId: id,
        note,
        authorType,
      },
    })

    return NextResponse.json({ success: true, reviewNote })
  } catch (error) {
    console.error('Error creating note:', error)
    return NextResponse.json(
      { success: false, error: 'Failed to create note' },
      { status: 500 }
    )
  }
}
GET function · typescript · L4-L36 (33 LOC)
app/api/applications/[id]/route.ts
export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params

    const application = await prisma.application.findUnique({
      where: { id },
      include: {
        reviewNotes: {
          orderBy: { createdAt: 'asc' },
        },
        certificate: true,
      },
    })

    if (!application) {
      return NextResponse.json(
        { success: false, error: 'Application not found' },
        { status: 404 }
      )
    }

    return NextResponse.json({ success: true, application })
  } catch (error) {
    console.error('Error fetching application:', error)
    return NextResponse.json(
      { success: false, error: 'Failed to fetch application' },
      { status: 500 }
    )
  }
}
PUT function · typescript · L38-L76 (39 LOC)
app/api/applications/[id]/route.ts
export async function PUT(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params
    const body = await request.json()
    const { description, aiPrecheckResult } = body

    const application = await prisma.application.update({
      where: { id },
      data: {
        description,
        aiPrecheckResult,
        status: 'SUBMITTED',
        reviewNotes: {
          create: {
            authorType: 'SYSTEM',
            note: 'Customer resubmitted application after corrections.',
          },
        },
      },
      include: {
        reviewNotes: {
          orderBy: { createdAt: 'asc' },
        },
        certificate: true,
      },
    })

    return NextResponse.json({ success: true, application })
  } catch (error) {
    console.error('Error updating application:', error)
    return NextResponse.json(
      { success: false, error: 'Failed to update application' },
      { status: 500 }
    )
  }
}
generateCertificateNumber function · typescript · L4-L8 (5 LOC)
app/api/applications/[id]/status/route.ts
function generateCertificateNumber(): string {
  const year = new Date().getFullYear()
  const random = Math.floor(Math.random() * 10000).toString().padStart(4, '0')
  return `ESG-${year}-${random}`
}
PUT function · typescript · L10-L70 (61 LOC)
app/api/applications/[id]/status/route.ts
export async function PUT(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params
    const body = await request.json()
    const { status, note } = body

    // Start with updating the application status
    const updateData: {
      status: string
      reviewNotes?: { create: { authorType: string; note: string } }
      certificate?: { create: { certificateNumber: string } }
    } = {
      status,
    }

    // Add a system note if provided
    if (note) {
      updateData.reviewNotes = {
        create: {
          authorType: 'STAFF',
          note,
        },
      }
    }

    // If approving, create a certificate
    if (status === 'APPROVED') {
      updateData.certificate = {
        create: {
          certificateNumber: generateCertificateNumber(),
        },
      }
    }

    const application = await prisma.application.update({
      where: { id },
      data: updateData,
      include: {
        reviewNote
GET function · typescript · L4-L34 (31 LOC)
app/api/applications/route.ts
export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url)
    const status = searchParams.get('status')
    const sortBy = searchParams.get('sortBy') || 'createdAt'
    const sortOrder = searchParams.get('sortOrder') || 'desc'

    const where = status && status !== 'all' ? { status } : {}

    const applications = await prisma.application.findMany({
      where,
      include: {
        reviewNotes: {
          orderBy: { createdAt: 'desc' },
        },
        certificate: true,
      },
      orderBy: {
        [sortBy]: sortOrder,
      },
    })

    return NextResponse.json({ success: true, applications })
  } catch (error) {
    console.error('Error fetching applications:', error)
    return NextResponse.json(
      { success: false, error: 'Failed to fetch applications' },
      { status: 500 }
    )
  }
}
POST function · typescript · L36-L70 (35 LOC)
app/api/applications/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const { applicantName, organizationName, email, sector, description, aiPrecheckResult } = body

    const application = await prisma.application.create({
      data: {
        applicantName,
        organizationName,
        email,
        sector,
        description,
        aiPrecheckResult,
        status: 'SUBMITTED',
        reviewNotes: {
          create: {
            authorType: 'SYSTEM',
            note: 'Application submitted for ESG certification review.',
          },
        },
      },
      include: {
        reviewNotes: true,
      },
    })

    return NextResponse.json({ success: true, application })
  } catch (error) {
    console.error('Error creating application:', error)
    return NextResponse.json(
      { success: false, error: 'Failed to create application' },
      { status: 500 }
    )
  }
}
POST function · typescript · L5-L171 (167 LOC)
app/api/market-directory/setup-advisor/route.ts
export async function POST(request: NextRequest) {
  try {
    const body = await request.json()
    const {
      sector,
      subSector,
      companySize,
      legalStructure,
      budget,
      priorities = [],
      additionalContext,
      locale = 'en',
    } = body as {
      sector: string
      subSector?: string
      companySize?: string
      legalStructure?: string
      budget?: string
      priorities?: string[]
      additionalContext?: string
      locale?: string
    }

    // Simulate AI processing delay (2-3 seconds)
    await new Promise((resolve) => setTimeout(resolve, 2200))

    const isArabic = locale === 'ar'

    // Find sector stats
    const sectorStat = sectorStats.find((s) => s.sector === sector)

    // Score each area based on input criteria
    const scoredAreas = areaStats.map((area) => {
      let score = 50 // base

      // Sector match — if area's top sectors include the requested sector
      if (area.topSectors.includes(sector)) {
        sc
Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
generateRationale function · typescript · L173-L185 (13 LOC)
app/api/market-directory/setup-advisor/route.ts
function generateRationale(area: AreaStat, sector: string, isArabic: boolean): string {
  const hasSector = area.topSectors.includes(sector)
  if (isArabic) {
    if (hasSector) {
      return `${area.areaAr} تضم بالفعل مجتمعاً نشطاً في قطاع ${sector}، مما يوفر فرص تواصل وتعاون. مستوى التشبع ${area.saturationLevel === 'Low' ? 'المنخفض' : area.saturationLevel === 'Medium' ? 'المتوسط' : 'المرتفع'} يعني مساحة للنمو.`
    }
    return `${area.areaAr} تقدم بيئة أعمال متنوعة مع بنية تحتية قوية. اتجاه النمو ${area.growthTrend === 'Growing' ? 'التصاعدي' : 'المستقر'} يشير إلى فرص واعدة.`
  }
  if (hasSector) {
    return `${area.area} already hosts an active ${sector} community, providing networking and collaboration opportunities. The ${area.saturationLevel.toLowerCase()} saturation level means room for growth.`
  }
  return `${area.area} offers a diverse business environment with strong infrastructure. The ${area.growthTrend.toLowerCase()} growth trend indicates promising opportunities.`
}
generateCompetitiveLandscape function · typescript · L187-L192 (6 LOC)
app/api/market-directory/setup-advisor/route.ts
function generateCompetitiveLandscape(area: AreaStat, sector: string, isArabic: boolean): string {
  if (isArabic) {
    return `${area.totalCompanies} شركة مسجلة في المنطقة. القطاعات الرئيسية: ${area.topSectorsAr.join('، ')}. متوسط الإيجار: ${area.averageRent}.`
  }
  return `${area.totalCompanies} registered companies in the area. Key sectors: ${area.topSectors.join(', ')}. Average rent: ${area.averageRent}.`
}
generateAdvantages function · typescript · L194-L209 (16 LOC)
app/api/market-directory/setup-advisor/route.ts
function generateAdvantages(area: AreaStat, isArabic: boolean): string[] {
  const infra = isArabic ? area.keyInfrastructureAr : area.keyInfrastructure
  const advantages = infra.slice(0, 3)

  if (area.growthTrend === 'Growing') {
    advantages.push(
      isArabic ? 'سوق نامي مع فرص متزايدة' : 'Growing market with increasing opportunities'
    )
  }
  if (area.saturationLevel === 'Low' || area.saturationLevel === 'Medium') {
    advantages.push(
      isArabic ? 'منافسة معتدلة — مساحة للداخلين الجدد' : 'Moderate competition — room for new entrants'
    )
  }
  return advantages
}
generateChallenges function · typescript · L211-L231 (21 LOC)
app/api/market-directory/setup-advisor/route.ts
function generateChallenges(area: AreaStat, isArabic: boolean): string[] {
  const challenges: string[] = []
  const rentNum = parseInt(area.averageRent.replace(/[^0-9]/g, ''))

  if (rentNum > 250) {
    challenges.push(
      isArabic ? 'تكاليف إيجار مرتفعة نسبياً' : 'Relatively high rental costs'
    )
  }
  if (area.saturationLevel === 'High' || area.saturationLevel === 'Very High') {
    challenges.push(
      isArabic ? 'سوق مشبع — يتطلب تمايز قوي' : 'Saturated market — requires strong differentiation'
    )
  }
  if (challenges.length === 0) {
    challenges.push(
      isArabic ? 'قد يتطلب بناء شبكة علاقات محلية' : 'May require building local network from scratch'
    )
  }
  return challenges
}
GET function · typescript · L4-L38 (35 LOC)
app/api/services/[id]/route.ts
export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params
    const serviceId = parseInt(id, 10)

    if (isNaN(serviceId)) {
      return NextResponse.json(
        { error: 'Invalid service ID' },
        { status: 400 }
      )
    }

    const service = await prisma.service.findUnique({
      where: { id: serviceId },
    })

    if (!service) {
      return NextResponse.json(
        { error: 'Service not found' },
        { status: 404 }
      )
    }

    return NextResponse.json(service)
  } catch (error) {
    console.error('Error fetching service:', error)
    return NextResponse.json(
      { error: 'Failed to fetch service' },
      { status: 500 }
    )
  }
}
GET function · typescript · L4-L55 (52 LOC)
app/api/services/route.ts
export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url)
    const platform = searchParams.get('platform')
    const department = searchParams.get('department')
    const search = searchParams.get('search')

    // Build where clause
    const where: Record<string, unknown> = {}

    if (platform) {
      where.platform = platform
    }

    if (department) {
      where.dept = department
    }

    if (search) {
      where.OR = [
        { name: { contains: search } },
        { nameAr: { contains: search } },
        { description: { contains: search } },
        { descriptionAr: { contains: search } },
      ]
    }

    const services = await prisma.service.findMany({
      where,
      orderBy: { name: 'asc' },
    })

    // Get unique departments and platforms for filters
    const allServices = await prisma.service.findMany({
      select: { dept: true, platform: true },
    })

    const departments = [...new Set(allServices.
GET function · typescript · L4-L41 (38 LOC)
app/api/staff/activity/route.ts
export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url)
    const page = parseInt(searchParams.get('page') || '1', 10)
    const pageSize = parseInt(searchParams.get('pageSize') || '15', 10)
    const skip = (page - 1) * pageSize

    const [entries, totalCount] = await Promise.all([
      prisma.activityLog.findMany({
        orderBy: { performedAt: 'desc' },
        skip,
        take: pageSize,
        include: {
          application: {
            select: {
              id: true,
              serviceType: true,
              submittedBy: true,
            },
          },
        },
      }),
      prisma.activityLog.count(),
    ])

    return NextResponse.json({
      success: true,
      entries,
      totalCount,
      page,
      pageSize,
      totalPages: Math.ceil(totalCount / pageSize),
    })
  } catch (error) {
    console.error('Error fetching activity log:', error)
    return NextResponse.json({ success: false, erro
GET function · typescript · L6-L35 (30 LOC)
app/api/staff/applications/[id]/route.ts
export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params

    const application = await prisma.baseApplication.findUnique({
      where: { id },
      include: {
        assignedTo: {
          select: { id: true, name: true, nameAr: true },
        },
        activityLogs: {
          orderBy: { performedAt: 'desc' },
          take: 50,
        },
      },
    })

    if (!application) {
      return NextResponse.json({ success: false, error: 'Application not found' }, { status: 404 })
    }

    return NextResponse.json({ success: true, application })
  } catch (error) {
    console.error('Error fetching application:', error)
    return NextResponse.json({ success: false, error: 'Failed to fetch application' }, { status: 500 })
  }
}
Want this analysis on your repo? https://repobility.com/scan/
PATCH function · typescript · L37-L110 (74 LOC)
app/api/staff/applications/[id]/route.ts
export async function PATCH(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const { id } = await params
    const body = await request.json()

    // Fetch current application
    const current = await prisma.baseApplication.findUnique({ where: { id } })
    if (!current) {
      return NextResponse.json({ success: false, error: 'Application not found' }, { status: 404 })
    }

    // Build update data
    const updateData: Record<string, unknown> = {}
    const actions: string[] = []

    if (body.status && body.status !== current.status) {
      updateData.status = body.status as StaffApplicationStatus
      actions.push(`Status changed from ${current.status} to ${body.status}`)

      // Set reviewedAt if moving to a terminal status
      const terminalStatuses = ['APPROVED', 'REJECTED', 'CLOSED']
      if (terminalStatuses.includes(body.status) && !current.reviewedAt) {
        updateData.reviewedAt = new Date()
        updateData.reviewe
GET function · typescript · L5-L81 (77 LOC)
app/api/staff/applications/route.ts
export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url)

    // Return staff list for assignment dropdown
    if (searchParams.get('staffList') === 'true') {
      const staffList = await prisma.staffUser.findMany({
        select: { id: true, name: true, nameAr: true },
        orderBy: { name: 'asc' },
      })
      return NextResponse.json({ success: true, staffList })
    }

    // Parse query params
    const serviceType = searchParams.get('serviceType') || ''
    const status = searchParams.get('status') || ''
    const assignedToId = searchParams.get('assignedToId') || ''
    const search = searchParams.get('search') || ''
    const page = parseInt(searchParams.get('page') || '1', 10)
    const pageSize = parseInt(searchParams.get('pageSize') || '10', 10)
    const sortBy = searchParams.get('sortBy') || 'submittedAt'
    const sortOrder = (searchParams.get('sortOrder') || 'desc') as 'asc' | 'desc'
    const skip = (page - 1) *
GET function · typescript · L4-L101 (98 LOC)
app/api/staff/stats/route.ts
export async function GET() {
  try {
    const now = new Date()
    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate())
    const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000)

    const [totalOpen, pendingReview, resolvedToday, avgResolution, countsByService, oldestPending] = await Promise.all([
      // Total open applications (not CLOSED, not REJECTED, not APPROVED)
      prisma.baseApplication.count({
        where: {
          status: { in: ['SUBMITTED', 'UNDER_REVIEW', 'PENDING_INFO'] },
        },
      }),

      // Pending review (SUBMITTED or UNDER_REVIEW)
      prisma.baseApplication.count({
        where: {
          status: { in: ['SUBMITTED', 'UNDER_REVIEW'] },
        },
      }),

      // Resolved today
      prisma.baseApplication.count({
        where: {
          reviewedAt: { gte: todayStart },
          status: { in: ['APPROVED', 'REJECTED', 'CLOSED'] },
        },
      }),

      // Average resolution time (last 30
page 1 / 4next ›