Skip to content

Backend Architecture

PIP AI uses a lightweight backend powered by Nuxt Nitro server routes and Supabase as the primary backend service.

Server Routes

All server routes are defined in server/api/ and follow Nitro conventions:

Admin Routes

RouteMethodHandlerPurpose
/api/admin/specs/uploadPOSTupload.post.tsUpload spec document and trigger processing
/api/admin/specs/callbackPOSTcallback.post.tsN8N callback after spec processing
/api/admin/specs/retryPOSTretry.post.tsRetry failed spec processing
/api/admin/brandsGETindex.get.tsList all brands
/api/admin/brandsPOSTindex.post.tsCreate a new brand
/api/admin/areasGETindex.get.tsList all areas
/api/admin/areasPOSTindex.post.tsCreate a new area

Export Routes

RouteMethodHandlerPurpose
/api/export/pdfPOSTpdf.post.tsGenerate PDF export
/api/export/render/[projectId]GET[projectId].get.tsRender project for export
/api/export/status/[jobId]GET[jobId].get.tsCheck export job status

Nano Banana (AI Image Generation)

RouteMethodHandlerPurpose
/api/nano-banana/jobsPOSTjobs.post.tsCreate image generation job
/api/nano-banana/jobsGETjobs.get.tsList jobs for a project
/api/nano-banana/messagesPOSTmessages.post.tsSend refinement message
/api/nano-banana/jobs/[jobId]/messagesGETmessages.get.tsGet chat history
/api/nano-banana/callbackPOSTcallback.post.tsN8N callback with results

Poly Haven (Material Library)

RouteMethodHandlerPurpose
/api/polyhaven/searchGETsearch.get.tsSearch Poly Haven textures
/api/polyhaven/categoriesGETcategories.get.tsGet texture categories
/api/polyhaven/info/[id]GET[id].get.tsGet asset details
/api/polyhaven/files/[id]GET[id].get.tsGet asset file URLs

Authentication in Server Routes

Server routes use the Supabase service role key to bypass RLS:

typescript
import { serverSupabaseServiceRole } from '#supabase/server'

export default defineEventHandler(async (event) => {
  const client = await serverSupabaseServiceRole(event)
  // Full database access, bypasses RLS
})

WARNING

The service role key has full database access. Always validate inputs and check permissions in server route handlers.

Webhook Security

N8N webhook callbacks are authenticated using a shared secret:

typescript
const secret = event.headers.get('x-webhook-secret')
if (secret !== useRuntimeConfig().n8nWebhookSecret) {
  throw createError({ statusCode: 401, message: 'Unauthorized' })
}

N8N Integration

Server routes trigger N8N workflows via HTTP webhooks:

typescript
// Trigger N8N workflow
await $fetch(`${config.public.n8nBaseUrl}${config.public.n8nWebhookSpecProcessor}`, {
  method: 'POST',
  headers: { 'x-webhook-secret': config.n8nWebhookSecret },
  body: {
    spec_upload_id: specUpload.id,
    document_id: document.id,
    storage_path: document.storage_path,
    brand_name: specUpload.brand_name,
    area: specUpload.area,
  }
})

Error Handling

Server routes use Nitro's createError for consistent error responses:

typescript
throw createError({
  statusCode: 400,
  message: 'Missing required field: projectId'
})

Built with VitePress