⚡ DepShield is running on a free Cloudflare Workers account for demo purposes, not production-grade infrastructure. Built for the Google Cloud Rapid Agent Hackathon.
Back to docs

Low Level Design (LLD)

DepShield : AI-Powered Dependency Intelligence Agent

Version: 1.0
Date: May 2026


1. Database Schema (Drizzle + Cloudflare D1)

typescript
// src/backend/db/schema.ts

import { sql } from 'drizzle-orm'
import { text, integer, sqliteTable } from 'drizzle-orm/sqlite-core'

// ─── Users ───────────────────────────────────────────────────
export const users = sqliteTable('users', {
  id: text('id').primaryKey(),                          // UUID
  googleId: text('google_id').unique().notNull(),
  email: text('email').unique().notNull(),
  name: text('name'),
  avatarUrl: text('avatar_url'),
  createdAt: integer('created_at').default(sql'(unixepoch())'),
  updatedAt: integer('updated_at').default(sql'(unixepoch())'),
})

// ─── PAT Tokens ──────────────────────────────────────────────
export const patTokens = sqliteTable('pat_tokens', {
  id: text('id').primaryKey(),                          // UUID
  userId: text('user_id').notNull()
    .references(() => users.id, { onDelete: 'cascade' }),
  platform: text('platform').notNull(),                 // 'github' | 'gitlab'
  encryptedToken: text('encrypted_token').notNull(),    // AES-256-GCM
  label: text('label'),                                 // "Work GitHub"
  lastUsedAt: integer('last_used_at'),
  createdAt: integer('created_at').default(sql'(unixepoch())'),
})

// ─── Scan Jobs ───────────────────────────────────────────────
export const scanJobs = sqliteTable('scan_jobs', {
  id: text('id').primaryKey(),                          // UUID
  userId: text('user_id')
    .references(() => users.id),                        // nullable (anonymous)
  repoUrl: text('repo_url').notNull(),
  platform: text('platform').notNull(),                 // 'github' | 'gitlab'
  ecosystem: text('ecosystem'),                         // 'nodejs' | 'python' etc
  packageManager: text('package_manager'),              // 'npm' | 'pnpm' | 'bun'
  status: text('status').default('pending'),            // pending|scanning|complete|error
  progress: integer('progress').default(0),
  totalPackages: integer('total_packages').default(0),
  error: text('error'),
  createdAt: integer('created_at').default(sql'(unixepoch())'),
  completedAt: integer('completed_at'),
})

// ─── Scan Results ────────────────────────────────────────────
export const scanResults = sqliteTable('scan_results', {
  id: text('id').primaryKey(),                          // UUID
  jobId: text('job_id').notNull()
    .references(() => scanJobs.id, { onDelete: 'cascade' }),
  totalPackages: integer('total_packages'),
  criticalCount: integer('critical_count').default(0),
  highCount: integer('high_count').default(0),
  mediumCount: integer('medium_count').default(0),
  lowCount: integer('low_count').default(0),
  safeCount: integer('safe_count').default(0),
  resultsJson: text('results_json'),                    // JSON stringified PackageRisk[]
  createdAt: integer('created_at').default(sql'(unixepoch())'),
})

// ─── Migration Jobs ──────────────────────────────────────────
export const migrationJobs = sqliteTable('migration_jobs', {
  id: text('id').primaryKey(),                          // UUID
  userId: text('user_id').notNull()
    .references(() => users.id),
  scanJobId: text('scan_job_id').notNull()
    .references(() => scanJobs.id),
  packageName: text('package_name').notNull(),          // "request"
  fromVersion: text('from_version'),                    // "^2.88.0"
  toPackage: text('to_package'),                        // "axios"
  toVersion: text('to_version'),                        // "^1.7.4"
  strategy: text('strategy').notNull(),                 // 'migrate' | 'version_bump'
  status: text('status').default('pending'),
  branchName: text('branch_name'),
  mrUrl: text('mr_url'),
  prUrl: text('pr_url'),
  filesChanged: integer('files_changed'),
  ciStatus: text('ci_status'),                          // 'passing' | 'failing'
  stepsJson: text('steps_json'),                        // JSON migration steps
  error: text('error'),
  createdAt: integer('created_at').default(sql'(unixepoch())'),
  completedAt: integer('completed_at'),
})

2. TypeScript Types

typescript
// src/types/index.ts

export type Platform = 'github' | 'gitlab'
export type Ecosystem = 'nodejs' | 'python' | 'go' | 'java' | 'ruby' | 'php' | 'rust'
export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun'
export type RiskLevel = 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW' | 'SAFE'
export type FixStrategy = 'migrate' | 'version_bump' | 'monitor'
export type ScanStatus = 'pending' | 'scanning' | 'complete' | 'error'
export type MigrationStatus = 
  | 'pending' 
  | 'analyzing' 
  | 'branching' 
  | 'transforming' 
  | 'committing' 
  | 'ci_running' 
  | 'creating_mr' 
  | 'complete' 
  | 'error'

export interface PackageRisk {
  name: string
  declaredVersion: string
  installedVersion?: string
  ecosystem: Ecosystem
  riskScore: number                    // 0-100
  riskLevel: RiskLevel
  fixStrategy: FixStrategy
  signals: RiskSignals
  explanation: string                  // Gemini generated
  recommendation?: string             // "Migrate to axios"
  alternative?: string                // "axios"
  alternativeCompatibility?: number   // 0-100
  cves: CVE[]
}

export interface RiskSignals {
  isDeprecated: boolean
  lastCommitDaysAgo: number
  downloadTrendPercent: number
  openCveCount: number
  maintainerActive: boolean
  weeklyDownloads: number
  communitySignal: string             // Elastic search result summary
}

export interface CVE {
  id: string                          // "CVE-2023-45857"
  severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW'
  affectedVersions: string[]
  fixedVersion?: string
  description: string
}

export interface MigrationStep {
  step: string
  status: 'pending' | 'running' | 'complete' | 'error'
  message?: string
  timestamp?: number
}

export interface EcosystemDetection {
  ecosystem: Ecosystem | null
  packageManager: PackageManager | null
  dependencyFile: string | null
  lockFile: string | null
  supported: boolean
}

export interface SimulationResult {
  simulationId: string
  fromPackage: string
  toPackage: string
  filesAffected: AffectedFile[]
  breakingChanges: string[]
  effortHours: number
  confidence: number
  codePreview: CodePreview
}

export interface AffectedFile {
  path: string
  linesChanged: number
  patterns: string[]
}

export interface CodePreview {
  file: string
  before: string
  after: string
}

3. Service Layer Interfaces

3.1 Scanner Service

typescript
// src/backend/services/scanner.service.ts

export interface ScannerService {
  detectEcosystem(repoUrl: string, token?: string): Promise<EcosystemDetection>
  parseDependencies(repoUrl: string, ecosystem: Ecosystem, token?: string): Promise<Record<string, string>>
  scanPackage(name: string, version: string, ecosystem: Ecosystem): Promise<PackageRisk>
  scanAllPackages(
    deps: Record<string, string>,
    ecosystem: Ecosystem,
    onProgress: (scanned: number, total: number) => void
  ): Promise<PackageRisk[]>
}

3.2 Elastic Service

typescript
// src/backend/services/elastic.service.ts

export interface ElasticService {
  indexPackageSignal(signal: PackageSignal): Promise<void>
  searchPackageHealth(packageName: string, ecosystem: string): Promise<ElasticSearchResult[]>
  searchMigrationGuides(fromPackage: string): Promise<MigrationGuide[]>
  findAlternatives(packageName: string, ecosystem: string): Promise<Alternative[]>
  bulkIndexSignals(signals: PackageSignal[]): Promise<void>
}

export interface PackageSignal {
  packageName: string
  ecosystem: string
  signalType: 'cve' | 'abandonment' | 'community' | 'deprecation' | 'alternative'
  signalText: string
  source: string
  date: string
  sentimentScore: number
}

3.3 GitLab Service

typescript
// src/backend/services/gitlab.service.ts

export interface GitLabService {
  getFile(repoUrl: string, filePath: string, token: string): Promise<string>
  listFiles(repoUrl: string, token: string): Promise<string[]>
  searchCode(repoUrl: string, query: string, token: string): Promise<CodeSearchResult[]>
  createBranch(repoUrl: string, branchName: string, token: string): Promise<void>
  commitFiles(repoUrl: string, branch: string, files: FileCommit[], token: string): Promise<void>
  triggerPipeline(repoUrl: string, branch: string, token: string): Promise<string>
  getPipelineStatus(repoUrl: string, pipelineId: string, token: string): Promise<PipelineStatus>
  createMergeRequest(repoUrl: string, mr: CreateMRInput, token: string): Promise<string>
}

3.4 GitHub Service

typescript
// src/backend/services/github.service.ts

export interface GitHubService {
  getFile(repoUrl: string, filePath: string, token?: string): Promise<string>
  listFiles(repoUrl: string, token?: string): Promise<string[]>
  searchCode(repoUrl: string, query: string, token: string): Promise<CodeSearchResult[]>
  createBranch(repoUrl: string, branchName: string, token: string): Promise<void>
  commitFiles(repoUrl: string, branch: string, files: FileCommit[], token: string): Promise<void>
  createPullRequest(repoUrl: string, pr: CreatePRInput, token: string): Promise<string>
  getCommitActivity(owner: string, repo: string): Promise<CommitActivity>
}

3.5 OSV Service

typescript
// src/backend/services/osv.service.ts

export interface OSVService {
  queryCVEs(packageName: string, ecosystem: string, version?: string): Promise<CVE[]>
  batchQueryCVEs(packages: PackageQuery[]): Promise<Map<string, CVE[]>>
}

export interface PackageQuery {
  name: string
  ecosystem: string
  version?: string
}

3.6 Migration Service

typescript
// src/backend/services/migration.service.ts

export interface MigrationService {
  simulate(input: SimulateInput): Promise<SimulationResult>
  execute(input: MigrateInput, onStep: (step: MigrationStep) => void): Promise<MigrationResult>
  transformCode(file: string, content: string, fromPkg: string, toPkg: string): Promise<string>
  generateMRDescription(result: MigrationResult): Promise<string>
}

4. Hono Route Handlers

typescript
// src/api/[[...route]]/route.ts

import { Hono } from 'hono'
import { handle } from 'hono/vercel'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'

const app = new Hono().basePath('/api')

// ─── Scan ─────────────────────────────────────────────────────
app.post('/scan', 
  zValidator('json', z.object({
    repoUrl: z.string().url(),
    token: z.string().optional(),
  })),
  async (c) => {
    const { repoUrl, token } = c.req.valid('json')
    // Create job, push to queue, return jobId
  }
)

// ─── Status ───────────────────────────────────────────────────
app.get('/status/:jobId',
  async (c) => {
    const jobId = c.req.param('jobId')
    // Fetch from KV first, fallback to D1
  }
)

// ─── Simulate ─────────────────────────────────────────────────
app.post('/simulate',
  zValidator('json', z.object({
    jobId: z.string(),
    packageName: z.string(),
    repoUrl: z.string().url(),
    token: z.string().optional(),
  })),
  async (c) => { }
)

// ─── Migrate ──────────────────────────────────────────────────
app.post('/migrate',
  zValidator('json', z.object({
    jobId: z.string(),
    packageName: z.string(),
    repoUrl: z.string().url(),
    platform: z.enum(['github', 'gitlab']),
    token: z.string(),
  })),
  async (c) => { }
)

app.get('/migrate/:migrationId', async (c) => { })

// ─── Tokens ───────────────────────────────────────────────────
app.post('/tokens', async (c) => { })
app.delete('/tokens/:id', async (c) => { })
app.get('/tokens', async (c) => { })

export const GET = handle(app)
export const POST = handle(app)
export const DELETE = handle(app)

5. Encryption Utility

typescript
// src/backend/util/encryption.ts

const ALGORITHM = 'AES-GCM'

export const encryptToken = async (token: string, key: string): Promise<string> => {
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    new TextEncoder().encode(key.padEnd(32).slice(0, 32)),
    ALGORITHM,
    false,
    ['encrypt']
  )
  const iv = crypto.getRandomValues(new Uint8Array(12))
  const encrypted = await crypto.subtle.encrypt(
    { name: ALGORITHM, iv },
    cryptoKey,
    new TextEncoder().encode(token)
  )
  const combined = new Uint8Array(iv.length + encrypted.byteLength)
  combined.set(iv)
  combined.set(new Uint8Array(encrypted), iv.length)
  return btoa(String.fromCharCode(...combined))
}

export const decryptToken = async (encrypted: string, key: string): Promise<string> => {
  const combined = Uint8Array.from(atob(encrypted), c => c.charCodeAt(0))
  const iv = combined.slice(0, 12)
  const data = combined.slice(12)
  const cryptoKey = await crypto.subtle.importKey(
    'raw',
    new TextEncoder().encode(key.padEnd(32).slice(0, 32)),
    ALGORITHM,
    false,
    ['decrypt']
  )
  const decrypted = await crypto.subtle.decrypt(
    { name: ALGORITHM, iv },
    cryptoKey,
    data
  )
  return new TextDecoder().decode(decrypted)
}

6. Elastic Index Mappings

json
{
  "mappings": {
    "properties": {
      "package_name":    { "type": "keyword" },
      "ecosystem":       { "type": "keyword" },
      "signal_type":     { "type": "keyword" },
      "signal_text":     { "type": "text", "analyzer": "english" },
      "signal_embedding":{ "type": "dense_vector", "dims": 768, "index": true, "similarity": "cosine" },
      "source":          { "type": "keyword" },
      "date":            { "type": "date" },
      "sentiment_score": { "type": "float" },
      "weekly_downloads":{ "type": "long" },
      "commit_count":    { "type": "integer" }
    }
  }
}

7. Environment Variables

typescript
// cloudflare-env.d.ts

interface CloudflareEnv {
  // D1
  DB: D1Database

  // KV
  KV: KVNamespace

  // Queues
  SCAN_QUEUE: Queue
  MIGRATION_QUEUE: Queue

  // Secrets
  ENCRYPTION_KEY: string
  NEXTAUTH_SECRET: string
  GOOGLE_CLIENT_ID: string
  GOOGLE_CLIENT_SECRET: string

  // Elastic
  ELASTIC_URL: string
  ELASTIC_API_KEY: string
  ELASTIC_MCP_ENDPOINT: string

  // GitHub
  GITHUB_TOKEN: string

  // Google Cloud
  GOOGLE_CLOUD_PROJECT_ID: string
  GOOGLE_CLOUD_LOCATION: string
  VERTEX_AI_API_KEY: string
}

© 2026 DepShield. All rights reserved.