feat(boc): Complete Business Operations Center v1.0

- Go backend API with full CRUD for all modules (CRM, Sales, Finance, HR, Legal, Marketing, Support, Purchase, Inventory, Projects, Automation, Analytics)
- Rust analytics service with parallel report generation
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables, full migrations
- Redis cache, sessions, pub/sub
- Kafka event streaming with Zookeeper
- WebSocket hub for real-time updates
- Automation engine with cron jobs, workflows, event triggers
- JWT authentication, multi-tenant from start
- Docker Compose with all services
- Nginx reverse proxy with rate limiting
- Integration tests passing
- Feature gap analysis against Fortnox/Odoo/Visma

Refs: BOC-001
This commit is contained in:
Bernt
2026-07-12 12:41:35 +00:00
parent 4789a7fb48
commit 58ca4e68db
26666 changed files with 575891 additions and 2074516 deletions
+190
View File
@@ -0,0 +1,190 @@
# ATM Anomaly Detection API
## REST API Endpoints
### Health Check
```
GET /health
```
Response:
```json
{
"status": "healthy",
"model_loaded": true,
"model_version": "v1.0.0",
"timestamp": "2026-07-11T06:00:00Z"
}
```
### Single Image Prediction
```
POST /predict
Content-Type: multipart/form-data
image: <file>
atm_id: "atm_001" (optional)
camera_angle: "front" (optional)
```
Response:
```json
{
"success": true,
"atm_id": "atm_001",
"timestamp": "2026-07-11T06:00:00Z",
"detections": [
{
"class_id": 5,
"class_name": "skimming_device",
"confidence": 0.94,
"bbox": [0.45, 0.52, 0.57, 0.60],
"severity": 5,
"requires_action": true
}
],
"summary": {
"total_anomalies": 1,
"max_severity": 5,
"requires_action": true,
"anomaly_types": ["skimming_device"]
}
}
```
### Batch Prediction
```
POST /predict/batch
Content-Type: multipart/form-data
images: <file1>, <file2>, ...
```
Response:
```json
{
"success": true,
"results": [
{
"filename": "atm_001.jpg",
"detections": [...],
"summary": {...}
}
]
}
```
### Get ATM Status
```
GET /atm/{atm_id}/status
```
Response:
```json
{
"atm_id": "atm_001",
"location": {
"latitude": 59.3293,
"longitude": 18.0686
},
"last_check": "2026-07-11T05:30:00Z",
"status": "anomaly_detected",
"open_anomalies": 2,
"max_severity": 4
}
```
### Get Anomaly History
```
GET /atm/{atm_id}/anomalies?start_date=2026-07-01&end_date=2026-07-11
```
Response:
```json
{
"atm_id": "atm_001",
"period": {
"start": "2026-07-01",
"end": "2026-07-11"
},
"total_anomalies": 15,
"anomalies": [
{
"id": "anom_001",
"type": "graffiti",
"detected_at": "2026-07-10T14:23:00Z",
"confidence": 0.87,
"status": "resolved",
"resolved_at": "2026-07-10T16:00:00Z"
}
]
}
```
### Submit Annotation (Human Verification)
```
POST /anomalies/{anomaly_id}/verify
Content-Type: application/json
{
"verdict": "confirmed",
"notes": "Confirmed skimming device attached to card reader",
"verified_by": "technician_001"
}
```
## WebSocket API
Real-time anomaly alerts:
```javascript
const ws = new WebSocket('wss://api.landvex.com/ws/alerts');
ws.onmessage = (event) => {
const alert = JSON.parse(event.data);
console.log(`Critical anomaly at ${alert.atm_id}: ${alert.anomaly_type}`);
};
```
Alert format:
```json
{
"alert_id": "alert_001",
"atm_id": "atm_001",
"timestamp": "2026-07-11T06:00:00Z",
"severity": 5,
"anomaly_type": "skimming_device",
"confidence": 0.94,
"image_url": "https://cdn.landvex.com/captures/atm_001_20260711060000.jpg",
"location": {
"latitude": 59.3293,
"longitude": 18.0686
},
"recommended_action": "Dispatch security team immediately"
}
```
## Error Responses
```json
{
"success": false,
"error": {
"code": "INVALID_IMAGE",
"message": "Image format not supported. Use JPG or PNG.",
"details": {}
}
}
```
## Rate Limits
- `/predict`: 100 requests/minute
- `/predict/batch`: 10 requests/minute
- `/atm/*`: 1000 requests/minute
## Authentication
API key in header:
```
Authorization: Bearer {api_key}
```
+138
View File
@@ -0,0 +1,138 @@
# ATM Anomaly Detection Dataset Guide
## Overview
This guide describes how to prepare training data for the ATM anomaly detection model.
## Directory Structure
```
data/
├── raw/ # Original images from cameras
│ ├── atm_001_20260701_120000_front.jpg
│ ├── atm_001_20260701_120005_side.jpg
│ └── ...
├── processed/ # Resized and normalized images
│ └── ...
├── annotations/ # Label files
│ ├── atm_001_20260701_120000_front.txt
│ └── ...
└── splits/ # Train/val/test splits
├── train/
│ ├── images/
│ └── labels/
├── val/
│ ├── images/
│ └── labels/
└── test/
├── images/
└── labels/
```
## Image Naming Convention
Format: `{atm_id}_{timestamp}_{camera_angle}.jpg`
Examples:
- `atm_001_20260701120000_front.jpg`
- `atm_001_20260701120000_side.jpg`
- `atm_002_20260701123000_wide.jpg`
## Annotation Format (YOLO)
Each `.txt` file contains one line per object:
```
<class_id> <x_center> <y_center> <width> <height>
```
All values are normalized to [0, 1] relative to image dimensions.
Example:
```
0 0.45 0.52 0.12 0.08
5 0.78 0.35 0.05 0.03
```
## Class IDs
| ID | Class Name | Description |
|----|-----------|-------------|
| 0 | physical_damage | Visible damage to structure |
| 1 | vandalism | Intentional damage |
| 2 | graffiti | Unauthorized markings |
| 3 | dirt_debris | Excessive dirt or debris |
| 4 | obstruction | Objects blocking view/access |
| 5 | skimming_device | Card skimmer attached |
| 6 | suspicious_attachment | Unknown device attached |
| 7 | out_of_service | Machine not functioning |
| 8 | screen_damage | Cracked or broken screen |
| 9 | cash_jam | Cash dispenser issue |
| 10 | receipt_jam | Printer issue |
| 11 | lighting_failure | Poor or no lighting |
| 12 | camera_blind | Security camera blocked |
| 13 | network_down | Connectivity issue |
## Annotation Guidelines
### Bounding Boxes
- Tight fit around anomaly
- Include entire affected area
- Do not include unaffected surroundings
### Multiple Anomalies
- Each anomaly gets its own bounding box
- Overlapping boxes are OK
- Same-class overlaps: merge if touching
### Difficult Cases
- Partially visible anomalies: annotate visible portion
- Ambiguous cases: mark with low confidence
- False positives in training: do not annotate
## Data Collection Best Practices
### Camera Setup
- Resolution: minimum 1920x1080
- Angle: front-facing, eye-level
- Lighting: avoid extreme shadows
- Distance: capture full ATM in frame
### Coverage
- Multiple angles per ATM
- Different times of day
- Various weather conditions
- Both normal and anomalous states
### Minimum Dataset Size
- Training: 1000+ images per class
- Validation: 200+ images per class
- Test: 200+ images per class
## Augmentation Strategy
Applied during training:
- Horizontal flip (50%)
- Brightness ±20%
- Rotation ±5 degrees
- Scale 50-150%
Not applied (preserve realism):
- Vertical flip
- Extreme rotation
- Color distortion
## Quality Checks
Before training:
1. Verify all images load correctly
2. Check annotation format
3. Validate bounding boxes within image bounds
4. Ensure class distribution is reasonable
5. Remove duplicates
## Tools
- [LabelImg](https://github.com/tzutalin/labelImg) - GUI annotation tool
- [CVAT](https://cvat.org/) - Online annotation platform
- [Roboflow](https://roboflow.com/) - Dataset management