A production-grade Laravel application for aggregating, validating, and analyzing
monthly Excel performance reports submitted by organizational units across all zones.
- Overview
- Architecture
- How It Works
- Prerequisites
- Installation
- Environment Configuration
- Queue Worker
- Testing
- Deployment
- Contributing
- License
Bank Performance Aggregator is an internal web platform designed to eliminate the manual overhead of consolidating monthly performance reports. Each organizational unit submits a structured .xlsx file. The system ingests these files asynchronously, validates all records against reference tables, persists clean data into a relational database, and exposes a management dashboard with filtering, aggregation, and Excel export capabilities.
Without this system, the monthly review process involves:
- Manually collecting dozens of Excel files from different units
- Consolidating them into a master spreadsheet β error-prone and time-consuming
- No automated detection of invalid or duplicate records
- No way to generate ranked performance reports without hours of manual work
Bank Performance Aggregator automates all of that.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Browser Client β
β Blade + Alpine.js + Tailwind β
ββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ
β HTTP / JSON
ββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββ
β Laravel 13 Application β
β β
β βββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
β β Controllers β β Services β β Jobs β β
β β β β β β β β
β β UploadCtrl ββββΆβ ExcelParser ββββΆβ ProcessFile β β
β β ReportCtrl β β ValidationSvc β β β β
β β ExportCtrl β β AggregatorSvc β β β β
β βββββββββββββββββ βββββββββββββββββββ βββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Eloquent ORM + Repositories β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββΌβββββββββββββββββββ
β β β
βββββββββΌβββββββ βββββββββΌββββββββ ββββββββΌββββββββ
β MySQL 8+ β β Redis Queue β β Storage β
β Primary DB β β + Cache β β Uploads β
ββββββββββββββββ βββββββββββββββββ ββββββββββββββββ
| Layer | Responsibility |
|---|---|
Controllers |
Accept HTTP requests, delegate to services, return responses |
ExcelParserService |
Load .xlsx files, identify sheets, extract and normalize raw rows |
ValidationService |
Validate each row against reference tables with Redis-cached lookups |
AggregatorService |
Run grouped queries and compute performance statistics |
ProcessUploadedFileJob |
Async queue job β parse β validate β persist β report |
Repositories |
Decouple query logic from business logic |
User uploads one or more .xlsx files
β
βΌ
UploadController
β
βββ Validate file format and size
βββ Store file to disk
βββ Create Upload record (status: pending)
βββ Dispatch async job to Redis queue
β
βΌ
ProcessUploadedFileJob
β
βββ Parse both sheets
βββ Validate every row
β βββ Valid rows β saved to database
β βββ Invalid rows β logged with reason
β
βββ Update Upload status + stats
Key design decisions:
- Async processing β files are queued immediately after upload; the user does not wait for processing to complete.
- Idempotent inserts β re-uploading the same file does not create duplicate records.
- Soft validation β a single invalid row does not reject the entire file; only that row is skipped and logged.
- Redis caching β reference table lookups (zones, branches, employees) are cached to avoid repeated database hits during bulk validation.
| Dependency | Minimum Version | Notes |
|---|---|---|
| PHP | 8.4+ | Extensions: mbstring, zip, pdo_mysql, openssl, curl, fileinfo |
| Composer | 2.x | PHP dependency manager |
| MySQL | 8.0+ | Primary relational database |
| Redis | 7.x | Queue backend and cache |
| Node.js | 20 LTS | Asset compilation |
| npm | 10.x | β |
git clone https://github.com/your-org/bank-performance-aggregator.git
cd bank-performance-aggregator
composer install --no-dev --optimize-autoloader
npm ci && npm run buildcp .env.example .env
php artisan key:generateCreate the database:
CREATE DATABASE your_database
CHARACTER SET utf8
COLLATE utf8_unicode_ci;Run migrations and seed reference data:
php artisan migrate --seedphp artisan storage:linkphp artisan serveAPP_NAME="Bank Performance Aggregator"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://your-domain.com
APP_TIMEZONE=Asia/Tehran
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=your_database
DB_USERNAME=your_username
DB_PASSWORD=your_password
DB_CHARSET=utf8
DB_COLLATION=utf8_unicode_ci
CACHE_DRIVER=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=null
LOG_CHANNEL=daily
LOG_LEVEL=warning# Development
php artisan queue:work redis --tries=3 --timeout=120
# Production β use Supervisor[program:bpa-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/bpa/artisan queue:work redis --tries=3 --timeout=120
autostart=true
autorestart=true
numprocs=2
redirect_stderr=true
stdout_logfile=/var/log/bpa-worker.log
stopwaitsecs=120# Run all tests
php artisan test
# With code coverage
php artisan test --coverage --min=80php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan optimize
php artisan migrate --force
php artisan queue:restartserver {
listen 443 ssl http2;
server_name your-domain.com;
root /var/www/bpa/public;
client_max_body_size 20M;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
}- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Commit using Conventional Commits:
feat: add new feature fix: resolve a bug docs: update documentation refactor: restructure without behavior change test: add or update tests - Push and open a Pull Request
MIT Β© 2025