Skip to main content

Architecture

VulnTrack uses Next.js Server Actions instead of traditional REST endpoints. Server Actions provide a type-safe, RPC-style API that integrates seamlessly with React Server Components and Next.js App Router.

What are Server Actions?

Server Actions are asynchronous functions that run on the server and can be called directly from client or server components. They are marked with the 'use server' directive at the top of the file. Key Benefits:
  • Type-safe communication between client and server
  • Automatic request/response serialization
  • Built-in CSRF protection
  • Integrated with React’s Suspense and transitions
  • No need to manually define API routes

Server Action Pattern

All server actions in VulnTrack follow a consistent pattern:
export async function actionName(params: any) {
  // 1. Authentication check
  const session = await getServerSession(authOptions)
  if (!session?.user?.id) {
    return { success: false, error: "Unauthorized" }
  }

  // 2. Authorization/Team isolation
  const user = await prisma.user.findUnique({
    where: { id: session.user.id },
    select: { teamId: true, role: true }
  })

  // 3. Business logic
  try {
    const result = await prisma.model.operation({
      // operation details
    })

    // 4. Cache revalidation
    revalidatePath('/dashboard/...')

    // 5. Audit logging
    await logAudit("ACTION_NAME", "Entity", id, "Description")

    return { success: true, data: result }
  } catch (error) {
    return { success: false, error: "Error message" }
  }
}

Response Format

All server actions return a consistent response format:
success
boolean
required
Indicates whether the operation succeeded
data
object
The requested data or operation result (present on success)
error
string
Error message explaining what went wrong (present on failure)

Calling Server Actions

From Client Components

'use client'

import { createVulnerability } from '@/app/actions/vulnerabilities'
import { useTransition } from 'react'

export function CreateForm() {
  const [isPending, startTransition] = useTransition()

  async function handleSubmit(formData: FormData) {
    startTransition(async () => {
      const result = await createVulnerability({
        title: formData.get('title'),
        description: formData.get('description'),
        severity: formData.get('severity'),
      })

      if (result.success) {
        // Handle success
      } else {
        // Handle error: result.error
      }
    })
  }

  return (
    <form action={handleSubmit}>
      {/* form fields */}
      <button disabled={isPending}>Submit</button>
    </form>
  )
}

From Server Components

import { getVulnerabilities } from '@/app/actions/vulnerabilities'

export default async function VulnPage() {
  const result = await getVulnerabilities()

  if (!result.success) {
    return <div>Error: {result.error}</div>
  }

  return (
    <ul>
      {result.data.map(vuln => (
        <li key={vuln.id}>{vuln.title}</li>
      ))}
    </ul>
  )
}

Security Features

Multi-Tenant Isolation

All server actions enforce strict team isolation:
  • Users can only access resources within their team
  • Admins have elevated privileges but are still scoped to their team
  • Cross-tenant access attempts return “Unauthorized” errors

Session Management

Every action validates the user session:
const session = await getServerSession(authOptions)
if (!session?.user?.id) {
  return { success: false, error: "Unauthorized" }
}

Audit Logging

Critical operations are logged for compliance:
await logAudit("CREATE_VULNERABILITY", "Vulnerability", id, "Created vulnerability: XSS in API")

Rate Limiting

Some actions include rate limiting to prevent abuse:
import { rateLimit } from "@/lib/rate-limit"

if (!rateLimit("registration_attempt", 5, 60000)) {
  return { success: false, error: "Too many attempts. Please try again later." }
}

Error Handling

Server actions return structured errors instead of throwing:
try {
  // operation
  return { success: true, data: result }
} catch (error) {
  console.error("Operation failed:", error)
  return { success: false, error: "User-friendly error message" }
}

Next Steps

Authentication

Learn about NextAuth.js integration and session management

Vulnerabilities

Create, read, update, and delete vulnerability records

Teams

Manage team members and assignments

Scoring

Calculate DREAD, STRIDE, and CVSS scores

Build docs developers (and LLMs) love