Skip to Content
Platform APIOverview

Platform API

platform-api is the main BFF. It owns everything that isn’t AI or document processing: resumes and their versions, sharing & collaboration, users & tokens, notifications, stats, analytics ingest, Clerk/Svix webhooks, billing & subscription, and the account-pool admin console (managing relay keys, channels, and dynamic config). It is also the single Prisma migration writer.

  • Base URL (dev): http://localhost:3111
  • Global prefix: /api
  • Swagger UI: /api/docs
  • Auth: ClerkAuthGuard per controller — send a PAT or Clerk JWT

Sections

The response envelope

Every successful response is wrapped by a global interceptor:

{ "code": 200, "data": <your payload>, "message": "success", "timestamp": "2026-06-19T08:00:00.000Z" }

Always read your payload from data. Errors are shaped by a global exception filter — see Errors. Full details in Response envelope.

Validation

Request bodies are validated with class-validator and a global ValidationPipe({ transform: true, whitelist: true }):

  • Unknown fields are stripped — sending extra keys won’t error, they just won’t persist.
  • Type mismatches and missing required fields return 400 with a list of messages.

Resume content is a serialized JSON string, not a nested object. The backend treats it opaquely — your app owns the resume schema. Send content: JSON.stringify(resumeDoc) and parse it back on read.

Rate limits

A global ThrottlerGuard is active, and some routes tighten it further with @Throttle. Notable per-route limits:

RouteLimit
PATCH /api/resumes/:id60 / min
POST /api/resumes/:id/versions60 / min
POST /api/resumes/:id/duplicate10 / min
POST /api/users/feedback3 / min
POST /api/analytics/events120 / min

Exceeding a limit returns 429 Too Many Requests. Back off and retry.

Internal architecture

Every platform-api module shares one flat feature-module shape: <name>.controller.ts + <name>.service.ts + <name>.module.ts (+ dto/). Services inject PrismaService directly — there are zero repositories / ports / adapters in the codebase. Complexity only adds files, never changes the structure.

Extra files appear only when a real signal calls for them:

  • Domain invariants (permissions / state machine / optimistic lock) → <name>.entity.ts (a pure domain class) + <name>.errors.ts.
  • Domain events<name>.event.ts, with subscribers wiring up in a service’s onModuleInit.

resumes is the codebase’s one “golden template” carrying entity / errors / event:

  • Optimistic locking: Resume has a revision field. An update carrying baseRevision runs a conditional updateMany; a 0-row match throws ResumeConflictError409.
  • Field-level encryption: resume content is stored AES-256-GCM-encrypted (ENCRYPTION_SECRET_KEY) and decrypted on read.
  • Domain events: adding a comment emits CommentAddedEvent, which notifications subscribes to and fans out — decoupled from the request path.

platform-api owns the resume/user/notification/analytics/observability models — plus the billing & subscription (Plan, Subscription, Order, CreditWallet, CreditTransaction, BillingOperation, …), AI-quota, reconciliation, Clerk-mirror, and dynamic-config (AppConfig) models. For the full grouped list and cross-service conventions see Architecture & conventions.

Endpoint map

AreaEndpoints
Resumes/api/resumes, /api/resumes/mine, /api/resumes/:id, /api/resumes/:id/versions, /api/resumes/:id/duplicate
Sharing/api/resumes/shared/:shareId, /api/resumes/shared/:shareId/comments
Collaboration/api/resumes/:id/collaborators, /api/resumes/:id/comments
Users/api/users, /api/users/:id, /api/users/sync, /api/users/feedback
Tokens/api/users/me/personal-access-tokens
Billing/api/billing/plans, /api/billing/subscriptions, /api/billing/subscription, /api/billing/wallet, /api/billing/ai-entitlement
Admin billing/api/admin/plans, /api/admin/subscriptions, /api/admin/customers, /api/admin/wallets/:userId/adjust, /api/admin/orders
Notifications/api/notifications, /api/notifications/:id/read
Stats/api/stats, /api/stats/advanced, /api/stats/logs
Analytics/api/analytics/events
Webhooks/api/webhooks/clerk (Svix-signed; not for direct calls)
Last updated on