Skip to content

Latest commit

 

History

History
168 lines (131 loc) · 3.71 KB

File metadata and controls

168 lines (131 loc) · 3.71 KB

Backend Architecture (api-server)

Overview

The backend is a Cloudflare Worker that exposes a tRPC API. It handles authentication, database operations, and business logic.

Entry Point

File: src/server.ts

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response>
}
  • Handles CORS preflight (OPTIONS)
  • Routes /trpc/* to tRPC handler
  • Routes /health to health check
  • Returns 404 for unknown routes

tRPC Setup

Router Structure (src/root.ts)

export const appRouter = router({
  auth: authRouter,
  resume: resumeRouter,
  section: sectionRouter,
});

Context (src/trpc/context.ts)

Created for every request, contains:

  • db - Drizzle database instance
  • user - Clerk user object (or null)
  • userId - User ID string (or null)
  • env - Cloudflare environment bindings
  • clerkClient - Clerk SDK client

Middleware (src/trpc/middleware/auth.ts)

export const authMiddleware = middleware(async ({ ctx, next }) => {
  if (!ctx.user || !ctx.userId) {
    throw new TRPCError({ code: 'UNAUTHORIZED' });
  }
  return next({ ctx });
});

Procedures (src/trpc/index.ts)

  • publicProcedure - No auth required
  • protectedProcedure - Requires authenticated user

Database

Connection (src/db/index.ts)

export function createDb(d1: D1Database): Database {
  return drizzle(d1, { schema });
}

Schema (src/db/schema.ts)

  • users - User accounts
  • resumes - Resume documents
  • sections - Resume sections
  • accounts, sessions - Auth tables

Migrations (drizzle/)

  • SQL migration files generated by Drizzle Kit
  • Applied via wrangler d1 migrations apply

Procedures Detail

Resume Procedures (src/trpc/procedures/resume.ts)

resume.list

  • Returns all resumes for authenticated user
  • Excludes archived by default
  • Orders by updatedAt desc

resume.getById

  • Fetches resume with all sections
  • Validates user ownership
  • Returns sections ordered by order field

resume.create

  • Creates resume with default metadata
  • Default metadata includes:
    • personalInfo - Empty personal details
    • settings - Page size, fonts, colors, margins

resume.update

  • Updates resume metadata
  • Validates Zod schema
  • Updates updatedAt timestamp

resume.delete

  • Soft delete (sets isArchived = true)
  • Or hard delete if specified

Section Procedures (src/trpc/procedures/section.ts)

section.upsert

  • Creates or updates section
  • Content is JSON blob specific to section type
  • Handles ordering

section.reorder

  • Updates order field for multiple sections
  • Transaction-safe

Cloudflare Bindings

D1 Database

// wrangler.jsonc
"d1_databases": [{
  "binding": "bettaresume_d1",
  "database_name": "bettaresume",
  "database_id": "...",
  "migrations_dir": "./drizzle"
}]

Environment Variables (.dev.vars)

CLERK_SECRET_KEY=sk_test_...
CLERK_PUBLISHABLE_KEY=pk_test_...

Error Handling

tRPC errors are caught and logged:

onError({ path, error }) {
  console.error(`Error in tRPC handler on path '${path}':`, error);
}

Common error codes:

  • UNAUTHORIZED - Missing or invalid auth
  • NOT_FOUND - Resource doesn't exist
  • FORBIDDEN - User doesn't own resource
  • BAD_REQUEST - Validation failed
  • INTERNAL_SERVER_ERROR - Database or runtime error

Local Development

cd api-server
npx wrangler dev
  • Runs on port 4000
  • Uses local D1 database (.wrangler/state/v3/d1/)
  • Hot reloads on file changes

Deployment

npx wrangler deploy
  • Deploys to Cloudflare Workers
  • Uses production D1 database
  • Requires CLERK_SECRET_KEY in Cloudflare dashboard