Files
bank-flow/README.md
2026-07-22 15:38:08 +03:30

8.1 KiB

BankFlow

BankFlow is a Laravel API for creating and processing bank loan applications through configurable, type-specific workflows.

Each loan is assigned an immutable published workflow configuration when it is created. Administrators can create draft configurations, select and order supported stages, define stage-specific rules, and publish a new version for a loan type without changing loans already in progress.

Project status

The repository is currently under implementation. The domain enums, Eloquent models, factories, database schema, and local development seeder are implemented. The API routes, workflow engine, admin configuration endpoints, and Docker image have not yet been implemented.

The approved implementation plan is documented in Project Blueprint.

Documentation

Document Description
Challenge requirements Functional requirements, business rules, and deliverables
API reference Public routes, request bodies, responses, and processing rules
Project blueprint Architecture, models, database schema, workflow design, and test plan

Technology stack

  • PHP 8.4
  • Laravel 13
  • PostgreSQL
  • Eloquent ORM
  • Pest 4
  • Laravel Pint
  • Docker

Architecture

BankFlow uses a layered Laravel architecture with domain grouping and single-purpose Actions.

HTTP Request
    ↓
Form Request
    ↓
Controller
    ↓
Action
    ↓
Workflow Engine / Eloquent
    ↓
PostgreSQL

Important architectural decisions:

  • Controllers remain thin and contain no business rules.
  • Application operations use dedicated Action classes instead of a generic service layer.
  • Eloquent is used directly; no Repository layer is introduced.
  • Workflow stages are stateless classes with one responsibility each.
  • Loan processing is synchronous and runs inside one database transaction.
  • Row locking and database uniqueness constraints prevent duplicate stage execution.
  • Expected business outcomes are persisted as loan history; Laravel logs are reserved for unexpected operational errors.
  • Queues, microservices, CQRS, Event Sourcing, and a generic Rule Engine are outside the project scope.

Configurable workflows

Workflow configuration is stored in PostgreSQL and belongs to a specific loan_type_id.

LoanType
    └── WorkflowConfiguration
            └── WorkflowConfigurationStep
                    └── StageDefinition

Configuration lifecycle:

  1. An administrator creates a draft for a loan type.
  2. Supported stages are selected and ordered.
  3. Stage-specific rules are stored as validated JSON.
  4. The complete workflow is validated.
  5. Publishing archives the previous version and makes the new version immutable.
  6. New loans use the new published version.
  7. Existing loans continue using their originally assigned version.

The database stores stable stage codes, not executable PHP or SQL. A trusted application registry maps each code to its handler class.

Domain model

Primary models:

  • LoanType
  • StageDefinition
  • WorkflowConfiguration
  • WorkflowConfigurationStep
  • Loan
  • LoanHistory

The domain keeps three concepts separate:

Concept Values
Loan status SUBMITTED, IN_PROGRESS, MANUAL_REVIEW, APPROVED, REJECTED
Workflow stage VALIDATION, FRAUD_CHECK, GUARANTOR_CHECK, CREDIT_CHECK, MANAGER_APPROVAL
Stage result PASS, FAIL, MANUAL_REVIEW

Default workflows

Personal loan

VALIDATION
    ↓
FRAUD_CHECK
    ↓
CREDIT_CHECK
    ↓
MANAGER_APPROVAL (when applicable)
    ↓
APPROVED

Business loan

VALIDATION
    ↓
FRAUD_CHECK
    ↓
GUARANTOR_CHECK
    ↓
CREDIT_CHECK
    ↓
MANAGER_APPROVAL (when applicable)
    ↓
APPROVED

A FAIL result immediately rejects the loan. A MANUAL_REVIEW result stops automatic processing and moves the loan to manual review.

Public API

Method Route Description
POST /api/v1/loans Create a loan application
POST /api/v1/loans/{loanId}/process Process all remaining workflow stages
GET /api/v1/loans/{loanId} Get a loan application
GET /api/v1/loans/{loanId}/history Get processing history
GET /health Check service health

One call to the process route runs all remaining applicable stages until the loan becomes APPROVED, REJECTED, or MANUAL_REVIEW. Calling it again after a terminal status returns the current state without rerunning stages or adding history.

See API Reference for request and response examples.

Prerequisites

For local development:

  • PHP 8.4 with the PostgreSQL extension
  • Composer
  • PostgreSQL
  • Node.js and npm for frontend asset compilation

Laravel Herd may be used for the local PHP runtime and site management.

Local setup

Install dependencies and create the environment file:

composer install
cp .env.example .env
php artisan key:generate
npm install

Configure PostgreSQL in .env:

DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=bankflow
DB_USERNAME=postgres
DB_PASSWORD=

Initialize the database and load development sample data with:

php artisan migrate --seed

DatabaseSeeder runs BankFlowDevelopmentSeeder only in the local environment. It creates:

  • an admin user (admin@bankflow.test / password);
  • PERSONAL and BUSINESS loan types;
  • all supported stage definitions;
  • one published workflow per loan type with configured rules;
  • submitted, approved, rejected, and manual-review loan examples;
  • processing histories linked to the exact workflow steps used.

For a clean development rebuild, use php artisan migrate:fresh --seed. This command deletes all existing database data.

Build frontend assets when required:

npm run build

Testing

Run the complete Pest suite:

php artisan test --compact

Run a focused test:

php artisan test --compact --filter=ProcessLoanTest

The planned suite covers:

  • unit tests for every workflow stage;
  • workflow order, stopping behavior, and rule validation;
  • workflow configuration draft and publication behavior;
  • public API feature tests;
  • admin configuration authorization and validation;
  • idempotent and concurrent processing;
  • PostgreSQL persistence and history ordering.

Code style

Format modified PHP files with:

vendor/bin/pint --dirty --format agent

Docker

The completed project must support the challenge commands:

docker build -t bankflow .
docker run -p 8080:8080 bankflow

The service must become ready within 60 seconds and preserve loan data across an application process restart.

Current status: the required Dockerfile has not been implemented yet, so these commands do not work in the current repository state.

Planned project structure

app/
├── Actions/
│   ├── Loan/
│   └── WorkflowConfiguration/
├── Domain/
│   └── Loan/
│       ├── Contracts/
│       ├── Data/
│       ├── Enums/
│       └── Workflow/
├── Http/
│   ├── Controllers/
│   ├── Requests/
│   └── Resources/
└── Models/

database/
├── factories/
├── migrations/
└── seeders/

tests/
├── Feature/
└── Unit/

The complete file and class layout is defined in Project Blueprint.

Implementation principles

  • Do not add behavior that is absent from the requirements or approved blueprint.
  • Do not allow clients to select workflow_configuration_id; the server selects the published configuration for the requested loan type.
  • Do not edit a published workflow configuration. Create and publish a new version.
  • Do not store executable class names, PHP, SQL, or unrestricted expressions in admin-managed rules.
  • Do not perform business validation in a way that bypasses workflow history.
  • Do not process one stage per API call; one process request runs to a terminal automatic-processing status.
  • Keep documentation synchronized with the implemented behavior.