← back to Letsbegin

lib/sheets.ts

118 lines

/**
 * Google Sheets integration for tracking project progress
 * Uses the existing Google Sheets API configuration
 */

const SHEETS_WEBHOOK_URL = process.env.GOOGLE_SHEETS_WEBHOOK_URL || ''
const SHEETS_ID = process.env.GOOGLE_SHEETS_ID || ''

interface TrackingEvent {
  timestamp: string
  project: string
  step: 'prd_generated' | 'ralph_converted' | 'ralph_started' | 'story_completed' | 'ralph_finished'
  details: string
  status: 'success' | 'error' | 'in_progress'
  storyId?: string
  duration?: number
}

export async function trackEvent(event: TrackingEvent): Promise<boolean> {
  try {
    // Store locally in JSON file
    const fs = await import('fs')
    const path = await import('path')

    const trackingDir = path.join(process.cwd(), 'data')
    const trackingFile = path.join(trackingDir, 'tracking.json')

    if (!fs.existsSync(trackingDir)) {
      fs.mkdirSync(trackingDir, { recursive: true })
    }

    let events: TrackingEvent[] = []
    if (fs.existsSync(trackingFile)) {
      events = JSON.parse(fs.readFileSync(trackingFile, 'utf8'))
    }

    events.push({
      ...event,
      timestamp: event.timestamp || new Date().toISOString()
    })

    // Keep last 1000 events
    if (events.length > 1000) {
      events = events.slice(-1000)
    }

    fs.writeFileSync(trackingFile, JSON.stringify(events, null, 2))

    // If Google Sheets webhook is configured, send there too
    if (SHEETS_WEBHOOK_URL) {
      await fetch(SHEETS_WEBHOOK_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          values: [[
            event.timestamp,
            event.project,
            event.step,
            event.details,
            event.status,
            event.storyId || '',
            event.duration || ''
          ]]
        })
      })
    }

    return true
  } catch (error) {
    console.error('Failed to track event:', error)
    return false
  }
}

export async function getTrackingEvents(project?: string, limit = 50): Promise<TrackingEvent[]> {
  try {
    const fs = await import('fs')
    const path = await import('path')

    const trackingFile = path.join(process.cwd(), 'data', 'tracking.json')

    if (!fs.existsSync(trackingFile)) {
      return []
    }

    let events: TrackingEvent[] = JSON.parse(fs.readFileSync(trackingFile, 'utf8'))

    if (project) {
      events = events.filter(e => e.project === project)
    }

    return events.slice(-limit).reverse()
  } catch (error) {
    console.error('Failed to get tracking events:', error)
    return []
  }
}

export async function getProjectStats(project: string): Promise<{
  totalPRDs: number
  totalRalphRuns: number
  successRate: number
  lastActivity: string | null
}> {
  const events = await getTrackingEvents(project, 1000)

  const prdEvents = events.filter(e => e.step === 'prd_generated')
  const ralphRuns = events.filter(e => e.step === 'ralph_finished')
  const successfulRuns = ralphRuns.filter(e => e.status === 'success')

  return {
    totalPRDs: prdEvents.length,
    totalRalphRuns: ralphRuns.length,
    successRate: ralphRuns.length > 0 ? (successfulRuns.length / ralphRuns.length) * 100 : 0,
    lastActivity: events[0]?.timestamp || null
  }
}