mirror of
https://github.com/sortedcord/alemno-payments.git
synced 2026-07-22 04:02:49 +05:30
195 lines
6.3 KiB
Markdown
195 lines
6.3 KiB
Markdown
# Alemeno Payments
|
|
|
|
[](file:///home/sortedcord/Projects/alemno_payments/pyproject.toml)
|
|
[](file:///home/sortedcord/Projects/alemno_payments/app/app.py)
|
|
[](https://github.com/sortedcord/alemno-payments/actions/workflows/tests.yml)
|
|
[](https://github.com/sortedcord/alemno-payments/actions/workflows/lint.yml)
|
|
[](https://github.com/sortedcord/alemno-payments/actions/workflows/docker.yml)
|
|
[](https://github.com/sortedcord/alemno-payments/actions/workflows/security.yml)
|
|
|
|
An asynchronous transactional data cleaning, validation, and LLM powered categorization pipeline.
|
|
|
|
## Features
|
|
|
|
- Reads multi format dates and handles missing transaction IDs by auto generating unique fallbacks, and parses messy amounts with currency signs and commas cleanly.
|
|
- Offloads validation, spend conversion, and analysis to a Celery background worker backed by Redis.
|
|
- Integrates with the Google GenAI SDK (`gemini-2.5-flash-lite` 75% cheaper than `gemini-3.5-flash-lite with no tangible decrease in performance) using structured output schemas to categorize transaction records into database- defined custom categories.
|
|
- Uses Redis caching with a 24-hour TTL to store live exchange rates, falling back to a hardcoded rate of `93.0` if offline.
|
|
- Statistical Anomaly Detection:
|
|
- Flags transactions exceeding 3 times the account's median spend as statistical outliers.
|
|
- Flags domestic transactions in USD currency.
|
|
- Flags high value transactions and transactions with fraud indicative keywords.
|
|
|
|
[](https://drive.google.com/file/d/1yk0-pXClrOp0ccTiaO7tbXPHZg4EH1eE/view?usp=sharing)
|
|
|
|
[Technical Video](https://www.youtube.com/watch?v=Xjfyf1ct-0U)
|
|
|
|
_Click on the image to view the [Draw.io](https://drive.google.com/file/d/1yk0-pXClrOp0ccTiaO7tbXPHZg4EH1eE/view?usp=sharing) file_
|
|
|
|
## Self Hosting & Deployment
|
|
|
|
We publish production-ready images to **GitHub Container Registry (GHCR)**. You can pull them directly or run them via Docker Compose.
|
|
|
|
Create a `docker-compose.yml` file to host the entire stack (or just clone the repo and directly run `docker compose up -d` :
|
|
|
|
```yaml
|
|
version: "3.8"
|
|
|
|
services:
|
|
db:
|
|
image: postgres:16-alpine
|
|
container_name: alemno_db
|
|
ports:
|
|
- "5432:5432"
|
|
environment:
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: postgres
|
|
POSTGRES_DB: alemno_payments
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres -d alemno_payments"]
|
|
interval: 5s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
container_name: alemno_redis
|
|
ports:
|
|
- "6379:6379"
|
|
|
|
web:
|
|
image: ghcr.io/sortedcord/alemno-payments/web:latest
|
|
container_name: alemno_web
|
|
ports:
|
|
- "3000:3000"
|
|
environment:
|
|
- POSTGRES_HOST=db
|
|
- POSTGRES_PORT=5432
|
|
- POSTGRES_USER=postgres
|
|
- POSTGRES_PASSWORD=postgres
|
|
- POSTGRES_DB=alemno_payments
|
|
- REDIS_HOST=redis
|
|
- REDIS_PORT=6379
|
|
- REDIS_DB=0
|
|
- GEMINI_API_KEY=your-gemini-api-key
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
worker:
|
|
image: ghcr.io/sortedcord/alemno-payments/worker:latest
|
|
container_name: alemno_worker
|
|
environment:
|
|
- POSTGRES_HOST=db
|
|
- POSTGRES_PORT=5432
|
|
- POSTGRES_USER=postgres
|
|
- POSTGRES_PASSWORD=postgres
|
|
- POSTGRES_DB=alemno_payments
|
|
- REDIS_HOST=redis
|
|
- REDIS_PORT=6379
|
|
- REDIS_DB=0
|
|
- GEMINI_API_KEY=your-gemini-api-key
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
volumes:
|
|
postgres_data:
|
|
```
|
|
|
|
Launch the stack:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|
|
|
|
## Testing the API with curl
|
|
|
|
All API endpoints are prefixed with `/api/v1`. Below are copy-pasteable `curl` commands using the sample [transactions.csv](file:///home/sortedcord/Projects/alemno_payments/transactions.csv) dataset.
|
|
|
|
### 1. Upload CSV Transaction Data
|
|
|
|
Submit a CSV file for asynchronous processing.
|
|
|
|
```bash
|
|
curl -X POST -F "file=@transactions.csv" http://localhost:3000/api/v1/jobs/upload
|
|
```
|
|
|
|
_Response Example:_
|
|
|
|
```json
|
|
{
|
|
"filename": "transactions.csv",
|
|
"id": "c0249af1-c52d-4d49-9305-3d1a10f29e03",
|
|
"status": "pending",
|
|
"row_count_raw": null,
|
|
"row_count_clean": null,
|
|
"created_at": "2026-07-03T06:29:13.123456Z",
|
|
"completed_at": null,
|
|
"error_message": null
|
|
}
|
|
```
|
|
|
|
### 2. Check Job Status
|
|
|
|
Check the status of a job using the job ID returned by the upload endpoint.
|
|
|
|
```bash
|
|
curl http://localhost:3000/api/v1/jobs/c0249af1-c52d-4d49-9305-3d1a10f29e03/status
|
|
```
|
|
|
|
_Response Example (while processing):_
|
|
|
|
```json
|
|
{
|
|
"id": "c0249af1-c52d-4d49-9305-3d1a10f29e03",
|
|
"status": "processing",
|
|
"summary": null
|
|
}
|
|
```
|
|
|
|
### 3. Get Full Job Results
|
|
|
|
Retrieve the high-level summary along with all categorized and parsed transactions once the job is completed.
|
|
|
|
```bash
|
|
curl http://localhost:3000/api/v1/jobs/c0249af1-c52d-4d49-9305-3d1a10f29e03/results
|
|
```
|
|
|
|
### 4. List All Jobs
|
|
|
|
List all historical processing jobs. You can optionally filter by status (e.g. `pending`, `processing`, `completed`, `failed`).
|
|
|
|
```bash
|
|
# List all jobs
|
|
curl http://localhost:3000/api/v1/jobs
|
|
|
|
# List completed jobs only
|
|
curl "http://localhost:3000/api/v1/jobs?status=completed"
|
|
```
|
|
|
|
### 5. List Categories
|
|
|
|
List all available transaction categories sorted alphabetically.
|
|
|
|
```bash
|
|
curl http://localhost:3000/api/v1/categories
|
|
```
|
|
|
|
### 6. Create Custom Category
|
|
|
|
Add a new custom category. Newly uploaded transactions will dynamically map to this category during classification if identified by the LLM.
|
|
|
|
```bash
|
|
curl -X POST \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"name": "Subscription"}' \
|
|
http://localhost:3000/api/v1/categories
|
|
```
|