How adnanhjoy/joy-pay works
1. Overall shape
- This is a NestJS backend API for a payment gateway called Joy Pay.
- The application is organized by feature modules, with PostgreSQL + Prisma as the persistence layer and Swagger/OpenAPI for API documentation.
2. Core runtime boundary
- src/main.ts boots the Nest application.
- src/app.module.ts composes the major modules:
- auth
- merchant
- payment
- transaction
- webhook
- provider
- database/config
- src/config/* and src/database/* are the infrastructure layer that the feature modules depend on.
3. Persistence and domain model
- Prisma is the central data access layer.
- The schema is split across prisma/models/*.prisma and prisma/enums/*.prisma, with migrations in prisma/migrations.
- The main persisted entities are:
- Merchant
- PaymentSession
- Transaction
- WebhookLog
- The committed prisma/generated/* client indicates the app uses generated Prisma types directly in the codebase.
4. Authentication and request security
- There are two auth concerns:
- JWT auth in src/modules/auth using jwt.strategy.ts
- HMAC request signing in src/common/guards/api-key-auth.guard.ts and src/common/utils/hmac.util.ts
- The api-key.decorator.ts suggests some routes extract or validate API key metadata for signed requests.
- Architecturally, this means the API supports both session-style authentication and partner/merchant request verification.
5. Merchant management subsystem
- src/modules/merchant owns merchant lifecycle operations.
- It exposes a controller/service pair and DTOs for creating and returning merchant data.
- This module is likely the authoritative entry point for onboarding and managing merchants before they can initiate payments.
6. Payment initiation subsystem
- src/modules/payment handles payment creation and API-facing payment endpoints.
- create-payment.dto.ts and payment-response.dto.ts indicate a request/response boundary around payment initiation.
- This module likely orchestrates validation, merchant authorization, provider selection, and persistence of the payment session.
7. Provider abstraction and routing
- src/modules/provider is the integration boundary for payment rails.
- payment-provider.interface.ts defines the contract, while provider.factory.ts selects among implementations.
- The repo currently includes mock adapters for:
- bKash
- Nagad
- Card
- This is a clear adapter pattern: the payment flow is decoupled from any one provider implementation.
8. Transaction tracking
- src/modules/transaction is the ledger/audit layer for payment state changes.
- The presence of create-transaction.dto.ts and transaction.service.ts suggests transactions are persisted separately from the initial payment request.
- In architecture terms, this module is the system of record for payment lifecycle transitions.
9. Webhook delivery and event logging
- src/modules/webhook handles webhook behavior.
- webhook.service.ts and webhook.controller.ts indicate both internal processing and an API surface.
- The persisted WebhookLog model suggests webhook attempts/statuses are tracked for reliability and auditability.
- This module is likely the outbound event boundary after a payment reaches success/failure states.
10. Cross-cutting infrastructure
- src/common contains shared concerns used across modules:
- auth decorators and guards
- HMAC utilities
- src/database/prisma.service.ts provides the shared database connection/service abstraction.
- src/config/app-config.service.ts and configuration.ts centralize runtime configuration such as database and JWT settings.
11. External/system dependencies
- The main external runtime dependency is PostgreSQL.
- The payment-provider layer is designed to represent external payment networks, but in this repo they are currently mock providers rather than real integrations.
- Swagger is a documentation surface, not a runtime dependency, but it affects how the API is consumed.
12. Primary data flow
- A typical flow is:
- merchant authenticates / is validated
- merchant submits a payment request
- payment module creates a payment session
- provider factory routes to the chosen provider adapter
- transaction records are written to PostgreSQL
- webhook events are logged/sent after status changes
- This makes the system a payment orchestration backend, not just a CRUD API.
13. Testing and delivery
- test/app.e2e-spec.ts and test/test-helpers.ts indicate the repo includes end-to-end API tests.
- The project uses standard Nest/TypeScript tooling (nest-cli.json, tsconfig*, ESLint, Prettier), so the architecture is optimized for a conventional server-side deployment pipeline.
14. What to draw in an architecture diagram
- Place NestJS API in the center with feature modules around it.
- Show PostgreSQL/Prisma as the persistence boundary.
- Show merchant clients entering through authenticated API routes.
- Show provider adapters as an internal abstraction layer between payment orchestration and payment networks.
- Show webhooks as an outbound event channel with logging/audit storage.
Main entry points: app.module.ts App module · prisma.service.ts Prisma service · payment.module.ts Payment · provider.module.ts Provider
Components 20
Runtime
NestJS bootstrap and application composition
- Bootstrap · Starts the application from src/main.ts
src/main.ts - App module · Composes the main feature and infrastructure modules
src/app.module.ts
Feature modules
API modules that implement the business flow
- Auth · JWT-based authentication boundary
src/modules/auth/auth.module.ts - Merchant · Merchant onboarding and management API
src/modules/merchant/merchant.module.ts - Payment · Creates payment sessions and exposes payment endpoints
src/modules/payment/payment.module.ts - Provider · Routes payment requests to a provider implementation
src/modules/provider/provider.module.ts - Transaction · Persists lifecycle changes and payment audit records
src/modules/transaction/transaction.module.ts - Webhook · Handles outbound webhook delivery and logging
src/modules/webhook/webhook.module.ts
Infrastructure
Shared config, security, and database wiring
- Config · Centralized application configuration values
src/config/configuration.ts - App config · Reads and exposes app settings such as JWT and database config
src/config/app-config.service.ts - Database · Wires Prisma into the NestJS app
src/database/database.module.ts - Prisma service · Shared Prisma connection and query access
src/database/prisma.service.ts - API security · HMAC request signing and API key metadata handling
src/common/guards/api-key-auth.guard.ts - HMAC util · Shared signing and verification logic for partner requests
src/common/utils/hmac.util.ts
Data layer
Prisma schema, generated client, and PostgreSQL boundary
- Prisma schema · Defines enums and models for merchants, payments, transactions, and webhooks
prisma/schema.prisma - Prisma client · Committed generated client types used by the codebase
prisma/generated/client.ts - PostgreSQL · Primary persistence store behind Prisma
External
Consumers and outside systems
- Merchant clients · External callers that authenticate and initiate payments
- Payment rails · bKash, Nagad, and card providers represented through adapters
- API docs · Swagger/OpenAPI description of the API surface
API_DOCUMENTATION.md
Connections 26
- Bootstrap → App module: boots · Application starts by creating the Nest app and loading the root module
- App module → Config: loads · Root composition depends on centralized runtime configuration
- App module → Database: imports · Application includes the database infrastructure module
- App module → Auth: composes · Root module wires the authentication feature
- App module → Merchant: composes · Root module wires merchant operations
- App module → Payment: composes · Root module wires payment initiation flows
- App module → Provider: composes · Root module wires provider abstraction and adapters
- App module → Transaction: composes · Root module wires transaction tracking
- App module → Webhook: composes · Root module wires webhook handling
- App module → API security: shares · Cross-cutting request verification is used across modules
- Database → Prisma service: provides · Database module exports the shared Prisma service
- Prisma service → Prisma schema: maps · Prisma service operates on the defined schema models
- Prisma schema → Prisma client: generates · Schema produces the committed Prisma client
- Prisma client → PostgreSQL: queries · Generated client is the access layer to PostgreSQL
- Auth → App config: uses · JWT auth reads runtime settings from config service
- API security → HMAC util: verifies · Guard relies on HMAC utilities for request signing checks
- Merchant → Prisma service: persists · Merchant lifecycle operations read and write through Prisma
- Payment → Prisma service: persists · Payment creation stores payment session data
- Payment → Provider: dispatches · Payment flow selects and invokes a provider adapter
- Payment → Transaction: records · Successful or failed payment steps are captured as transactions
- Payment → Webhook: emits · Payment state changes trigger webhook handling and logging
- Provider → Payment rails: adapts · Provider layer represents the external payment networks
- Transaction → Prisma service: persists · Transaction records are stored in the database
- Webhook → Prisma service: logs · Webhook attempts and status are persisted for auditability
- Merchant clients → API security: calls · Merchant-facing requests enter through authenticated and signed routes
- API docs → App module: describes · API documentation documents the NestJS endpoints