Skip to content

bisa-kerja/bisakerja-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

107 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bisakerja API

Backend API for the Bisakerja platform. This service owns authentication, user workflows, job discovery API contracts, application tracking, AI workflow orchestration, persistence access, runtime validation, and the public REST boundary consumed by the frontend.

Bisakerja is an AI-assisted career decision platform for Indonesian job seekers. The backend exists to provide a stable product API for finding relevant jobs, understanding job fit, improving CV quality, and tracking application outcomes.

Table of Contents

Overview

The Bisakerja Backend API is the main application backend for Bisakerja. It provides the frontend-facing REST API, validates user input, enforces authentication and ownership rules, formats consistent API responses, and coordinates data access through PostgreSQL and Prisma.

This repository is responsible for:

  • Auth, session, email verification, password reset, and Google OAuth workflows
  • User profile, preference, bookmark, CV file, and application tracker workflows
  • Job search and job detail access over normalized job records
  • AI CV Analyzer orchestration through the Model API boundary, including CV feedback, fit alignment, and embedded job recommendations
  • Internal scraper sync and notification handoff endpoints protected by service credentials
  • Prisma schema, migrations, seed data, and repository-level persistence logic
  • Service-owned technical documentation and generated API artifacts
  • Docker-based runtime deployment support for a VPS-style environment

The backend should not behave as a generic pass-through proxy. It should shape responses around product workflows, protect private user data, and translate downstream failures into frontend-safe API responses.

Platform Context

Bisakerja is positioned as a decision layer for Indonesian job seekers, not only as a job listing interface. The product combines job discovery, profile and preference context, fit scoring, explainable recommendations, CV feedback, and application tracking.

The broader platform includes:

Service Responsibility
Frontend UI Presents discovery, fit analysis, CV analysis, preferences, and tracking UI
Backend API Owns business workflows, auth, persistence access, and API contracts
Scraper API Collects and normalizes external job data
Model API Produces fit scores, explanations, skill gaps, and CV analysis output
PostgreSQL Stores users, jobs, preferences, applications, and AI result snapshots

The frontend calls the Backend API for product workflows. It must not call Scraper API or Model API directly.

Service Boundary

The Backend API owns:

  • Authentication and authorization decisions
  • User profile, preference, bookmark, and application tracker workflows
  • Backend-facing validation with Zod
  • API response formatting and error mapping
  • Prisma-based database access for backend-owned records
  • Product-friendly formatting of Model API outputs
  • Read access to normalized job records required by search, detail, and AI workflows

The Backend API does not own:

  • Frontend rendering or client-side state
  • Scraping, parsing, and normalization logic for external job platforms
  • Model training, model artifact management, or low-level inference internals
  • Central platform documentation governance outside service-owned backend docs

MVP Modules

Module Responsibility
Auth Register, login, logout, refresh/session, password reset, email verification, and Google OAuth
Users Account profile, onboarding state, career background, skills, and education
Preferences Career status, target roles, locations, work types, salary, and notifications
Jobs Search, filter, sort, list, detail, company data, source data, and apply links
Bookmarks Save, remove, list saved jobs, duplicate handling, and ownership checks
Applications Track user-specific applications, status changes, and status history
CV Files Upload reusable user CV PDFs and expose safe active-file metadata
AI CV Analyzer Analyze uploaded or stored CV PDFs against target job roles; return fit alignment, ATS feedback, section reviews, top actions, and embedded job recommendations
AI CV Generate Generate safe markdown HTML CV content from an owned stored CV, structured summary, and sanitized template input
Shared CV Evidence Keep Analyzer wrapper and Generate flows on one sanitized evidence schema without retaining raw CV text, prompts, provider payloads, or secrets
AI Job Fit Retired standalone route; fit-style output now lives in CV Analyzer analysisResult.jobFitAlignment
AI Job Recommendations Retired standalone route; compact recommendations now live in CV Analyzer analysisResult.jobRecommendations
Internal Accept scraper job sync payloads and notification handoff events through service-token auth
Health Liveness and readiness endpoints

Future modules such as mentoring, notification expansion, analytics, payments, and direct ATS integration are documented as future scope and should not block MVP behavior.

API Surface

Default local base URL:

http://localhost:3000/api/v1

Key route groups:

Route group Prefix Auth class
Health /health/live, /health/ready Public or infrastructure-restricted
Auth /api/v1/auth Public plus authenticated session routes
Users /api/v1/me Authenticated
Preferences /api/v1/me/preferences Authenticated or onboarding access token
Jobs /api/v1/jobs Public for search and detail
Bookmarks /api/v1/me/bookmarks Authenticated and ownership-protected
Applications /api/v1/me/applications Authenticated and ownership-protected
CV Files /api/v1/me/cv-files Authenticated or onboarding access token
AI CV Analyzer /api/v1/ai/cv-analyzer Authenticated
AI CV Generate /api/v1/ai/cv-generate Authenticated and ownership-protected
Internal /api/v1/internal Service-token protected

JSON responses use a consistent envelope with success, message, data, meta, and error fields. See docs/api-response-standard.md for the full response contract.

Documentation Map

Use this reading order when onboarding or reviewing changes:

  1. docs/overview.md for service purpose, scope, and ownership boundaries.
  2. docs/api-reference.md for route groups, auth classification, API docs, and generated contract workflow.
  3. docs/project-structure.md for folder layout, module anatomy, and dependency direction.
  4. docs/environment.md for runtime variables and environment separation.
  5. docs/database.md for Prisma, PostgreSQL, entity ownership, and migration policy.
  6. docs/operations/testing.md for test strategy and verification commands.
  7. docs/operations/deployment.md for runtime deployment assumptions.
  8. docs/modules/*.md for module-specific behavior and endpoint details, including docs/modules/shared-cv-evidence.md for AI evidence safety rules.
  9. docs/generated/openapi.json and docs/generated/routes.md for generated API artifacts.

Tech Stack

Area Choice
Runtime Bun 1.3.3
Language TypeScript
HTTP framework Express.js 5
Database PostgreSQL
ORM Prisma 7
Validation Zod
Logging Pino
Security Helmet, CORS, rate limits
Auth JWT, refresh-token cookies
Async jobs Redis + BullMQ + DB outbox
Email Fake provider or Resend
API docs OpenAPI and Scalar
Testing bun test
Formatting Prettier
Linting ESLint

Getting Started

Install dependencies:

bun install

Create local environment files:

cp .env.example .env
cp .env.test.example .env.test

Generate the Prisma client:

bun run prisma:generate

Apply migrations to your configured development database:

bun run prisma:migrate:dev

Seed deterministic local data:

bun run prisma:seed

Start the API in watch mode:

bun run dev

Start the API without watch mode:

bun run start

Start the async worker:

bun run worker:async

The default local API runs at:

http://localhost:3000

Environment Configuration

The app validates environment variables at startup. Missing required values or invalid values should fail before the server accepts requests.

Environment contract is explicit:

  • DATABASE_URL and DIRECT_DATABASE_URL must both be set.
  • SEED_USER_PASSWORD must be set before running bun run prisma:seed.
  • MODEL_API_SERVICE_TOKEN, SCRAPER_API_SERVICE_TOKEN, and RESEND_API_KEY must stay non-empty even in local fake/mock setups; use safe placeholders when the real integration is disabled.
  • The repository does not rely on env fallback values anymore.

Important local files:

File Purpose
.env.example Local development baseline
.env.test.example Test environment baseline
.env.production.example Deployment-oriented baseline for Docker Compose

Important variable groups:

  • Application: APP_ENV, NODE_ENV, PORT, API_PREFIX, APP_URL, FRONTEND_URL
  • Database: DATABASE_URL, DIRECT_DATABASE_URL, SEED_USER_PASSWORD, RUN_DATABASE_TESTS
  • Auth: access-token secret, refresh-token secret, TTLs, cookie settings
  • Security: CORS origins, trusted proxy, body limit, rate limit settings
  • Async workloads: REDIS_URL, queue name/prefix, concurrency, retry/backoff, recovery interval
  • Integrations: Model API URL/token, Scraper API service token, email provider, job freshness threshold
  • Uploads: storage driver, upload path, CV limits, retention
  • Observability: log level, request id header, health timeout

Do not commit real secrets or production database credentials.

Database Workflow

PostgreSQL is the durable source of truth. Runtime environments are expected to use managed or externally hosted PostgreSQL through DATABASE_URL.

For providers such as Neon or Supabase:

  • Use DATABASE_URL for the runtime connection, usually the provider pooler URL.
  • Use DIRECT_DATABASE_URL for Prisma migrations and seed flows.
  • Use a separate database for tests.
  • Keep RUN_DATABASE_TESTS=false for ordinary local test runs unless an isolated test database is prepared.

Common commands:

bun run prisma:validate
bun run prisma:generate
bun run prisma:migrate:dev
bun run prisma:migrate:deploy
bun run prisma:seed
bun run prisma:verify:migrations

Available Scripts

Script Purpose
bun run dev Start the API in watch mode
bun run start Start the API
bun run typecheck Run TypeScript contract checks
bun run lint Run ESLint
bun run format Format files with Prettier
bun run format:check Check formatting without writing
bun test Run the default test suite
bun run test:unit Run unit tests
bun run test:routes Run route/API contract tests
bun run test:integration Run integration tests
bun run test:contracts Run downstream contract tests
bun run test:smoke Run smoke tests
bun run test:coverage Run full suite with coverage report
bun run docs:generate:openapi Regenerate OpenAPI artifact
bun run docs:generate:routes Regenerate route inventory
bun run docs:generate:sync-readiness Regenerate sync-readiness inventory
bun run docs:prepare:sync-bundle Prepare documentation sync bundle
bun run docs:check Verify documentation metadata and examples
bun run docs:scalar:check-config Validate Scalar Docs configuration
bun run docs:scalar:preview Preview repo documentation through Scalar Docs
bun run cleanup:cv-uploads Enqueue expired temporary CV cleanup job
bun run worker:async Start Redis-backed async worker
bun run prisma:reset Reset local database without reseeding
bun run prisma:reset:seed Reset local database and reseed deterministic data

Testing And Verification

Fast local verification:

bun run typecheck
bun run lint
bun run format:check
bun test
bun run test:coverage
bun run docs:check

Database-backed tests require an isolated test database and RUN_DATABASE_TESTS=true. Do not point these tests at development, staging, or production data. Schema changes that affect async jobs also require applying Prisma migrations to the test database before DB-backed verification.

Documentation or route changes may also require:

bun run docs:generate:openapi
bun run docs:generate:routes
bun run docs:generate:sync-readiness
bun run docs:scalar:check-config

Migration-affecting changes should run:

bun run prisma:verify:migrations

API Documentation

The backend exposes generated API documentation in repo and at runtime:

Surface Path
Generated OpenAPI file docs/generated/openapi.json
Generated route inventory docs/generated/routes.md
Runtime OpenAPI endpoint /openapi.json
Runtime Scalar viewer /docs/api
Scalar Docs config scalar.config.json

Recommended local workflow:

  1. Start the backend with bun run dev.
  2. Open http://localhost:3000/docs/api.
  3. Use http://localhost:3000/openapi.json when tooling needs the raw OpenAPI document.

When routes or contracts change, update the implementation, update relevant module docs, regenerate generated artifacts, and run docs verification before merging.

Project Structure

.
|-- prisma/
|   |-- migrations/
|   |-- schema.prisma
|   |-- seed-data.ts
|   `-- seed.ts
|-- src/
|   |-- app.ts
|   |-- server.ts
|   |-- config/
|   |-- core/
|   |-- modules/
|   `-- shared/
|-- tests/
|   |-- unit/
|   |-- integration/
|   |-- smoke/
|   `-- fixtures/
|-- docs/
|   |-- generated/
|   |-- modules/
|   `-- operations/
|-- docker-compose.yml
|-- Dockerfile
|-- package.json
`-- scalar.config.json

Feature modules live under src/modules/<module>/ and generally follow this shape:

<module>.route.ts
<module>.controller.ts
<module>.service.ts
<module>.repository.ts
<module>.schema.ts
<module>.types.ts
<module>.constants.ts
index.ts

Routes define the HTTP shape, controllers coordinate input/output, services own business rules, repositories own Prisma queries, and schemas own Zod validation.

Deployment Notes

The repository includes Docker and Compose support for running the application container. The active Compose file runs app, worker, and redis; PostgreSQL is still expected to be provided externally.

Deployment expectations:

  • Build a reproducible image from committed source and bun.lock.
  • Provide runtime secrets through environment variables or a deployment env file.
  • Run Prisma migrations explicitly before serving production traffic.
  • Keep the async worker deployed as a separate long-running process from the HTTP app.
  • Keep Redis durable enough for queue availability and let PostgreSQL outbox remain the source of truth for missed publishes.
  • Keep upload storage outside the application artifact.
  • Use /health/live for process liveness and /health/ready for dependency readiness.
  • Keep staging and production databases, secrets, and CORS origins separate.

Compose commands:

bun run docker:compose:config
bun run docker:compose:pull
bun run docker:compose:up
bun run docker:compose:down

Contribution Guide

Before changing behavior:

  • Read the relevant module doc in docs/modules/**.
  • Keep module boundaries aligned with docs/project-structure.md.
  • Update tests with the smallest coverage that proves the changed behavior.
  • Update all related documentation in the same work item when adding a feature, fixing a bug, changing an env contract, or changing runtime/ops behavior.
  • Update generated OpenAPI and route inventory when route contracts change.
  • Update environment examples and docs/environment.md when variables change.
  • Update database docs and migration verification when Prisma schema changes.

Before opening a PR or handing off a change, run the relevant verification commands for the touched area and document any checks that require external credentials or a live database.

About

Backend service for Bisakerja, providing RESTful APIs for authentication, job data, user preferences, and AI integration.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages