Skip to content

Service Architecture ​

Service Communication Pattern ​

All services communicate via HTTP REST APIs through API Gateway. No direct service-to-service communication.

Service Inventory ​

Main API (peoplehub-api) ​

Purpose: Core HRMS functionality

Responsibilities:

  • Employee management (personal data, employment details, documents)
  • Leave and attendance management
  • Performance management (OKRs, reviews)
  • Recruitment (jobs, candidates, interviews)
  • Separation workflows
  • Talent and demand management
  • Settings and master data
  • User and role management

Tech Stack: Node.js 22, Fastify, Drizzle ORM Database: Shared RDS PostgreSQL Endpoints: 150+ REST endpoints API Documentation: /docs endpoint (Scalar UI)

Candidate Onboarding API (candidate-api) ​

Purpose: Isolated onboarding workflows for security

Responsibilities:

  • Candidate personal information collection
  • Document uploads (pre-joining)
  • Background verification workflows
  • Policy acknowledgment
  • E-signature integration (Digio)
  • Onboarding task tracking

Tech Stack: Node.js 18, Fastify, Drizzle ORM Database: Shared RDS PostgreSQL (separate credentials) Security Isolation: Separate Lambda, separate domain, limited database access API Documentation: /docs endpoint

Integration API (integration-api) ​

Purpose: External system integrations and scheduled jobs

Responsibilities:

  • Digio webhook handling (e-signature status updates)
  • ATS integration (TalentRecruit - planned)
  • Payroll system sync (planned)
  • Workforce management integration (planned)
  • Scheduled cron jobs (data sync, cleanup tasks)

Tech Stack: Node.js 20, Fastify, Drizzle ORM Database: Shared RDS PostgreSQL Deployment: Separate Lambda with extended timeout (for long-running sync jobs)

Notifications Service (notifications-api) ​

Purpose: Email notification engine

Responsibilities:

  • Receive notification trigger requests
  • Fetch email templates from database
  • Populate templates with dynamic data
  • Send emails via AWS SES
  • Log notification delivery status

Tech Stack: Node.js 18, Fastify, AWS SES Database: Shared RDS PostgreSQL (read templates) Email Provider: AWS SES (Simple Email Service)

PDF Generation Service (pdf-service) ​

Purpose: Generate PDF documents from HTML templates

Responsibilities:

  • Receive PDF generation requests
  • Render HTML templates with data
  • Convert to PDF using Weazy Print
  • Return PDF file or upload to S3

Tech Stack: Python 3.11, Weazy Print library Why Python: Weazy Print is the best HTML-to-PDF library, only available in Python Deployment: Separate Lambda with Python runtime

Inter-Service Communication ​

Main API → Notifications API ​

Trigger: Events requiring email notifications Pattern: HTTP POST to /notifications/triggerData: Template ID, recipient, dynamic data Example: Employee leave approved → notify employee and manager

Main API → PDF Service ​

Trigger: Document generation requests Pattern: HTTP POST to /pdf/generateData: HTML template, data payload Example: Generate offer letter PDF for new hire

Candidate API → Notifications API ​

Trigger: Onboarding events Pattern: HTTP POST to /notifications/triggerExample: Candidate completes onboarding → notify HR team

Integration API → Main API ​

Trigger: External data sync Pattern: HTTP POST to main API endpoints Example: ATS pushes new candidate → create in recruitment module

External Systems → Integration API ​

Trigger: Webhook events Pattern: HTTP POST to /webhooks/{provider}Example: Digio sends e-signature completed event

Database Access Pattern ​

All services share the same RDS PostgreSQL instance but with different access levels:

Main API: Full read/write access to all tables Candidate API: Limited access (only onboarding-related tables) Integration API: Full read/write (for sync operations) Notifications API: Read-only access (fetch templates) PDF Service: No direct database access (receives data via API)

API Versioning ​

Current: v1 (implicit) Future: /v2/ prefix for breaking changes Strategy: Maintain backward compatibility, deprecate old versions gradually

Service Discovery ​

No service discovery needed. All services accessed via:

  • Frontend → API Gateway → Lambda (AWS handles routing)
  • Service-to-service → HTTP calls via base URL (environment variable)

Error Handling ​

Standard error response format across all services:

  • HTTP status codes (400, 401, 404, 500, etc.)
  • JSON error body with message and code
  • Errors logged to CloudWatch for debugging

Authentication Between Services ​

Frontend → Backend: JWT in HTTP-only cookie Service → Service: API key authentication (for internal calls) External Systems → Integration API: Webhook secrets or API keys

Load Balancing ​

API Gateway automatically distributes requests across Lambda instances. No manual load balancer configuration needed.

Service Isolation Benefits ​

  1. Security: Candidate data isolated from main system
  2. Scaling: Each service scales independently based on load
  3. Deployment: Deploy services independently without downtime
  4. Fault Isolation: One service failure doesn't affect others
  5. Technology Choice: Use best tool for each service (Node vs Python)