complete docs
This commit is contained in:
506
docs/api-routes.md
Normal file
506
docs/api-routes.md
Normal file
@@ -0,0 +1,506 @@
|
||||
# BankFlow API Reference
|
||||
|
||||
This document describes the HTTP API contract for BankFlow. It is based on the requirements in [bank-flow.md](./bank-flow.md).
|
||||
|
||||
## Overview
|
||||
|
||||
All loan routes are versioned under `/api/v1`. The health-check route is not versioned.
|
||||
|
||||
### Routes
|
||||
|
||||
| Method | Route | Description | Success status |
|
||||
|--------|----------------------------------|----------------------------|----------------|
|
||||
| `POST` | `/api/v1/loans` | Create a loan application | `201 Created` |
|
||||
| `POST` | `/api/v1/loans/{loanId}/process` | Process a loan application | `200 OK` |
|
||||
| `GET` | `/api/v1/loans/{loanId}` | Get a loan application | `200 OK` |
|
||||
| `GET` | `/api/v1/loans/{loanId}/history` | Get processing history | `200 OK` |
|
||||
| `GET` | `/health` | Check service health | `200 OK` |
|
||||
|
||||
## General conventions
|
||||
|
||||
### Content type
|
||||
|
||||
Requests with a body must use JSON. Every response must include:
|
||||
|
||||
```http
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### Timestamps
|
||||
|
||||
All timestamps use ISO 8601 format in UTC:
|
||||
|
||||
```text
|
||||
2026-07-15T10:00:00Z
|
||||
```
|
||||
|
||||
### Loan types
|
||||
|
||||
| Value | Description |
|
||||
|------------|---------------|
|
||||
| `PERSONAL` | Personal loan |
|
||||
| `BUSINESS` | Business loan |
|
||||
|
||||
### Loan statuses
|
||||
|
||||
| Status | Description | Terminal for automatic processing |
|
||||
|-----------------|----------------------------------------------------|-----------------------------------|
|
||||
| `SUBMITTED` | The application has been created but not processed | No |
|
||||
| `IN_PROGRESS` | The application is being processed | No |
|
||||
| `MANUAL_REVIEW` | The application requires a manual decision | Yes |
|
||||
| `APPROVED` | The application has been approved | Yes |
|
||||
| `REJECTED` | The application has been rejected | Yes |
|
||||
|
||||
### Loan stages
|
||||
|
||||
| Stage | Description |
|
||||
|--------------------|-----------------------------------------|
|
||||
| `VALIDATION` | Validate the submitted application data |
|
||||
| `FRAUD_CHECK` | Perform the mocked fraud check |
|
||||
| `GUARANTOR_CHECK` | Check for a guarantor on business loans |
|
||||
| `CREDIT_CHECK` | Evaluate the applicant's credit score |
|
||||
| `MANAGER_APPROVAL` | Apply the mocked manager-approval rule |
|
||||
|
||||
### Stage result type
|
||||
|
||||
| Result | Effect |
|
||||
|-----------------|------------------------------------------------------------|
|
||||
| `PASS` | Continue to the next applicable stage |
|
||||
| `FAIL` | Stop processing and set the loan status to `REJECTED` |
|
||||
| `MANUAL_REVIEW` | Stop processing and set the loan status to `MANUAL_REVIEW` |
|
||||
|
||||
## Create a loan application
|
||||
|
||||
Creates and stores a new loan application. Creating an application does not execute its workflow.
|
||||
|
||||
```http
|
||||
POST /api/v1/loans
|
||||
```
|
||||
|
||||
### Request body
|
||||
|
||||
| Field | Type | Required | Rules |
|
||||
|-----------------|-----------|----------|----------------------------------------------------|
|
||||
| `customerId` | `string` | Yes | Must not be empty |
|
||||
| `amount` | `integer` | Yes | Must be greater than `0` |
|
||||
| `phone` | `string` | Yes | Must contain exactly 11 digits and start with `09` |
|
||||
| `loanType` | `string` | Yes | Must be `PERSONAL` or `BUSINESS` |
|
||||
| `monthlyIncome` | `integer` | Yes | Must be greater than or equal to `0` |
|
||||
| `creditScore` | `integer` | Yes | Must be between `0` and `1000`, inclusive |
|
||||
| `hasGuarantor` | `boolean` | Yes | Indicates whether the applicant has a guarantor |
|
||||
|
||||
```json
|
||||
{
|
||||
"customerId": "C-1001",
|
||||
"amount": 400000000,
|
||||
"phone": "09121234567",
|
||||
"loanType": "PERSONAL",
|
||||
"monthlyIncome": 50000000,
|
||||
"creditScore": 720,
|
||||
"hasGuarantor": false
|
||||
}
|
||||
```
|
||||
|
||||
### Processing rules
|
||||
|
||||
- The service generates a unique `loanId`.
|
||||
- The initial status is `SUBMITTED`.
|
||||
- The initial workflow stage is `VALIDATION`.
|
||||
- Business validation is deferred until the workflow is processed.
|
||||
- An invalid field value does not produce an HTTP `400` response during creation. It causes the `VALIDATION` stage to fail when the application is processed.
|
||||
- A malformed JSON document produces an HTTP `400` response.
|
||||
|
||||
### Success response
|
||||
|
||||
```http
|
||||
HTTP/1.1 201 Created
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"loanId": "L-10001",
|
||||
"status": "SUBMITTED",
|
||||
"currentStage": "VALIDATION"
|
||||
}
|
||||
```
|
||||
|
||||
#### Response fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|----------------|----------|------------------------------------------------|
|
||||
| `loanId` | `string` | Unique identifier generated by the service |
|
||||
| `status` | `string` | Current loan status; initially `SUBMITTED` |
|
||||
| `currentStage` | `string` | Current workflow stage; initially `VALIDATION` |
|
||||
|
||||
### Malformed JSON response
|
||||
|
||||
```http
|
||||
HTTP/1.1 400 Bad Request
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "INVALID_REQUEST"
|
||||
}
|
||||
```
|
||||
|
||||
## Process a loan application
|
||||
|
||||
Processes an application from its current workflow stage until it reaches a terminal automatic-processing status.
|
||||
|
||||
```http
|
||||
POST /api/v1/loans/{loanId}/process
|
||||
```
|
||||
|
||||
### Path parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|----------|----------|------------------------------------|
|
||||
| `loanId` | `string` | Yes | Unique loan application identifier |
|
||||
|
||||
This route does not accept a request body.
|
||||
|
||||
### Workflow rules
|
||||
|
||||
All applications begin with the following stages:
|
||||
|
||||
```text
|
||||
VALIDATION → FRAUD_CHECK
|
||||
```
|
||||
|
||||
The remaining route depends on the loan type:
|
||||
|
||||
```text
|
||||
PERSONAL:
|
||||
VALIDATION → FRAUD_CHECK → CREDIT_CHECK → [MANAGER_APPROVAL] → APPROVED
|
||||
|
||||
BUSINESS:
|
||||
VALIDATION → FRAUD_CHECK → GUARANTOR_CHECK → CREDIT_CHECK
|
||||
→ [MANAGER_APPROVAL] → APPROVED
|
||||
```
|
||||
|
||||
`MANAGER_APPROVAL` runs only when `amount` is greater than the configured `managerApprovalThreshold`.
|
||||
|
||||
Processing stops immediately when a stage returns `FAIL` or `MANUAL_REVIEW`.
|
||||
|
||||
### Idempotency rules
|
||||
|
||||
This operation must be idempotent.
|
||||
|
||||
If the application is already `APPROVED`, `REJECTED`, or `MANUAL_REVIEW`:
|
||||
|
||||
- no workflow stage is executed again;
|
||||
- no duplicate history record is created;
|
||||
- the existing status is not changed;
|
||||
- the current application state is returned with `200 OK`.
|
||||
|
||||
### Approved response
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"loanId": "L-10001",
|
||||
"status": "APPROVED",
|
||||
"currentStage": null
|
||||
}
|
||||
```
|
||||
|
||||
### Rejected response
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"loanId": "L-10001",
|
||||
"status": "REJECTED",
|
||||
"currentStage": null
|
||||
}
|
||||
```
|
||||
|
||||
### Manual-review response
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"loanId": "L-10001",
|
||||
"status": "MANUAL_REVIEW",
|
||||
"currentStage": null
|
||||
}
|
||||
```
|
||||
|
||||
### Loan-not-found response
|
||||
|
||||
```http
|
||||
HTTP/1.1 404 Not Found
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "LOAN_NOT_FOUND"
|
||||
}
|
||||
```
|
||||
|
||||
## Get a loan application
|
||||
|
||||
Returns the submitted data and current processing state of a loan application.
|
||||
|
||||
```http
|
||||
GET /api/v1/loans/{loanId}
|
||||
```
|
||||
|
||||
### Path parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `loanId` | `string` | Yes | Unique loan application identifier |
|
||||
|
||||
### Success response
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"loanId": "L-10001",
|
||||
"customerId": "C-1001",
|
||||
"amount": 400000000,
|
||||
"phone": "09121234567",
|
||||
"loanType": "PERSONAL",
|
||||
"monthlyIncome": 50000000,
|
||||
"creditScore": 720,
|
||||
"hasGuarantor": false,
|
||||
"status": "APPROVED",
|
||||
"currentStage": null,
|
||||
"createdAt": "2026-07-15T10:00:00Z",
|
||||
"updatedAt": "2026-07-15T10:00:03Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Response fields
|
||||
|
||||
| Field | Type | Nullable | Description |
|
||||
|-----------------|-----------|----------|-------------------------------------------------------|
|
||||
| `loanId` | `string` | No | Unique loan application identifier |
|
||||
| `customerId` | `string` | No | Customer identifier |
|
||||
| `amount` | `integer` | No | Requested loan amount |
|
||||
| `phone` | `string` | No | Applicant's mobile number |
|
||||
| `loanType` | `string` | No | Loan type |
|
||||
| `monthlyIncome` | `integer` | No | Applicant's monthly income |
|
||||
| `creditScore` | `integer` | No | Applicant's credit score |
|
||||
| `hasGuarantor` | `boolean` | No | Whether the applicant has a guarantor |
|
||||
| `status` | `string` | No | Current loan status |
|
||||
| `currentStage` | `string` | Yes | Current workflow stage; `null` after processing stops |
|
||||
| `createdAt` | `string` | No | Creation timestamp in ISO 8601 UTC format |
|
||||
| `updatedAt` | `string` | No | Last-update timestamp in ISO 8601 UTC format |
|
||||
|
||||
### Loan-not-found response
|
||||
|
||||
```http
|
||||
HTTP/1.1 404 Not Found
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "LOAN_NOT_FOUND"
|
||||
}
|
||||
```
|
||||
|
||||
## Get processing history
|
||||
|
||||
Returns workflow stage executions in chronological order.
|
||||
|
||||
```http
|
||||
GET /api/v1/loans/{loanId}/history
|
||||
```
|
||||
|
||||
### Path parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|----------|----------|------------------------------------|
|
||||
| `loanId` | `string` | Yes | Unique loan application identifier |
|
||||
|
||||
### History rules
|
||||
|
||||
- Records are ordered by `timestamp` from oldest to newest.
|
||||
- A workflow stage is recorded at most once for an application.
|
||||
- Reprocessing a terminal application does not add history records.
|
||||
- `reason` contains `SUCCESS` for a successful stage or the applicable business error code for a failed validation.
|
||||
|
||||
### Success response
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"stage": "VALIDATION",
|
||||
"result": "PASS",
|
||||
"timestamp": "2026-07-15T10:00:00Z",
|
||||
"reason": "SUCCESS"
|
||||
},
|
||||
{
|
||||
"stage": "FRAUD_CHECK",
|
||||
"result": "PASS",
|
||||
"timestamp": "2026-07-15T10:00:01Z",
|
||||
"reason": "SUCCESS"
|
||||
},
|
||||
{
|
||||
"stage": "CREDIT_CHECK",
|
||||
"result": "PASS",
|
||||
"timestamp": "2026-07-15T10:00:02Z",
|
||||
"reason": "SUCCESS"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### History record fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------------|----------|----------------------------------------------------------|
|
||||
| `stage` | `string` | Name of the executed workflow stage |
|
||||
| `result` | `string` | `PASS`, `FAIL`, or `MANUAL_REVIEW` |
|
||||
| `timestamp` | `string` | Execution time in ISO 8601 UTC format |
|
||||
| `reason` | `string` | Reason or business error code associated with the result |
|
||||
|
||||
### Loan-not-found response
|
||||
|
||||
```http
|
||||
HTTP/1.1 404 Not Found
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "LOAN_NOT_FOUND"
|
||||
}
|
||||
```
|
||||
|
||||
## Health check
|
||||
|
||||
Reports whether the service is available.
|
||||
|
||||
```http
|
||||
GET /health
|
||||
```
|
||||
|
||||
### Success response
|
||||
|
||||
```http
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "UP"
|
||||
}
|
||||
```
|
||||
|
||||
## Business rules
|
||||
|
||||
### Validation
|
||||
|
||||
The `VALIDATION` stage applies the following rules:
|
||||
|
||||
| Field | Rule | Failure reason |
|
||||
|-----------------|---------------------------------------------------------------|--------------------------|
|
||||
| `customerId` | Required and not empty | `INVALID_CUSTOMER_ID` |
|
||||
| `amount` | Greater than `0` | `INVALID_AMOUNT` |
|
||||
| `phone` | Exactly 11 digits, starts with `09`, and contains digits only | `INVALID_PHONE` |
|
||||
| `loanType` | `PERSONAL` or `BUSINESS` | `INVALID_LOAN_TYPE` |
|
||||
| `monthlyIncome` | Greater than or equal to `0` | `INVALID_MONTHLY_INCOME` |
|
||||
| `creditScore` | Between `0` and `1000`, inclusive | `INVALID_CREDIT_SCORE` |
|
||||
|
||||
Any validation failure produces a `FAIL` stage result and changes the application status to `REJECTED`.
|
||||
|
||||
### Fraud check
|
||||
|
||||
The `FRAUD_CHECK` stage is mocked using `customerId`:
|
||||
|
||||
| Rule | Result |
|
||||
|----------------------|-----------------|
|
||||
| Starts with `FRAUD` | `FAIL` |
|
||||
| Starts with `REVIEW` | `MANUAL_REVIEW` |
|
||||
| Any other value | `PASS` |
|
||||
|
||||
### Guarantor check
|
||||
|
||||
The `GUARANTOR_CHECK` stage runs only for `BUSINESS` loans:
|
||||
|
||||
| Rule | Result |
|
||||
|---------------------------|--------|
|
||||
| `hasGuarantor` is `false` | `FAIL` |
|
||||
| `hasGuarantor` is `true` | `PASS` |
|
||||
|
||||
### Credit check
|
||||
|
||||
The default credit-score rules are:
|
||||
|
||||
| Rule | Result |
|
||||
|----------------------------|-----------------|
|
||||
| `creditScore < 500` | `FAIL` |
|
||||
| `500 <= creditScore < 650` | `MANUAL_REVIEW` |
|
||||
| `creditScore >= 650` | `PASS` |
|
||||
|
||||
The score boundaries must be loaded from configuration and must not be hard-coded.
|
||||
|
||||
### Manager approval
|
||||
|
||||
`MANAGER_APPROVAL` runs when the requested amount is greater than the configured `managerApprovalThreshold`.
|
||||
|
||||
| Rule | Result |
|
||||
|---------------------------------------------|--------|
|
||||
| `amount > monthlyIncome × incomeMultiplier` | `FAIL` |
|
||||
| Otherwise | `PASS` |
|
||||
|
||||
Both `managerApprovalThreshold` and `incomeMultiplier` must be loaded from configuration.
|
||||
|
||||
## Error codes
|
||||
|
||||
### HTTP errors
|
||||
|
||||
| HTTP status | Error code | Description |
|
||||
|-------------------|-------------------|------------------------------------------------------|
|
||||
| `400 Bad Request` | `INVALID_REQUEST` | The request body is not valid JSON |
|
||||
| `404 Not Found` | `LOAN_NOT_FOUND` | No loan application exists for the supplied `loanId` |
|
||||
|
||||
HTTP error responses use this shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "LOAN_NOT_FOUND"
|
||||
}
|
||||
```
|
||||
|
||||
### Business validation errors
|
||||
|
||||
Business validation errors do not produce HTTP `400` responses during loan creation. They are recorded as the `reason` of the failed `VALIDATION` history entry.
|
||||
|
||||
| Error code | Description |
|
||||
|--------------------------|------------------------------------|
|
||||
| `INVALID_AMOUNT` | The requested amount is invalid |
|
||||
| `INVALID_PHONE` | The mobile number is invalid |
|
||||
| `INVALID_CUSTOMER_ID` | The customer identifier is invalid |
|
||||
| `INVALID_LOAN_TYPE` | The loan type is invalid |
|
||||
| `INVALID_CREDIT_SCORE` | The credit score is invalid |
|
||||
| `INVALID_MONTHLY_INCOME` | The monthly income is invalid |
|
||||
1078
docs/project-blueprint.md
Normal file
1078
docs/project-blueprint.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user