Real-time invoice and contract inconsistency detection system built in Rust.
Fen automatically ingests, parses, and analyzes invoices and contracts at scale while detecting structural and semantic inconsistencies with sub-millisecond query times. The system combines modern document understanding models with a tiered storage architecture and multi-layer anomaly detection pipeline.
- Ingest 10,000+ documents/hour with automated structure extraction
- Sub-millisecond P99 query latency on hybrid SQL + vector queries
- Real-time inconsistency detection across structural, temporal, relational, and semantic dimensions
- Horizontal scaling to petabyte-scale document archives
- Strong consistency guarantees for financial audit compliance
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INGESTION TIER (fen-ingestion) β
β β
β βββββββββββββββ β
β β PDF Parser ββββ text + rendered pages β
β β (pdfium) β β
β βββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββ β
β βΌ βΌ β
β βββββ Text Path (fastest) βββββββ βββββ Image Path (scanned docs) ββββββββββββ
β β β β ββ
β β βββββββββββββββββββββββββ β β βββββββββββββ ββββββββββββββββββββββ ββ
β β β GLiNER Zero-Shot NER β β β β PaddleOCR ββ β LayoutLMv3 β ββ
β β β Medium β Large tier β β β β (PP-OCRv4)β β (layout + entities)β ββ
β β βββββββββββββββββββββββββ β β βββββββββββββ ββββββββββββββββββββββ ββ
β β β β β β ββ
β ββββββββββββββ¬ββββββββββββββββββββ β βΌ βΌ ββ
β β β βββββββββββ ββββββββββββββββββββββ ββ
β β β β TATR β β Donut (fallback) β ββ
β β β β (tables)β β imageβJSON <0.5 β ββ
β β β βββββββββββ ββββββββββββββββββββββ ββ
β β ββββββββββββ¬ββββββββββββββββββββββββββββββββ
β ββββββββββββββββ¬ββββββββββββββββββββ β
β βΌ β
β βββββ Entity Extraction (5-tier per field) ββββββββββββββββββββββββββββββββββββββ
β β LayoutLMv3 entities β KV pairs β GLiNER β Rule Engine β Regex ββ
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
β βββββ Post-Extraction ββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β βββββββββββββββββββ ββββ΄βββββββββββββββ βββββββββββββββββββββββββββββββ ββ
β β β Embedding Gen β β Invoice/Contractβ β Extraction Logger (JSONL) β ββ
β β β (MiniLM-L6-v2) β β Struct Builder β β β GLiNER fine-tuning data β ββ
β β βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββββββββββββββ ββ
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββ΄ββββββββββββββ
βΌ βΌ
ββββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββββββββββββ
β KNOWLEDGE GRAPH (fen-graph) β β STORAGE TIER (Distributed) β
β ββββββββββββββββββββββββββββββ β β β
β β KyuGraph (pure Rust) β β β ββββββββββββββββ ββββββββββββββββ βββββββββ
β β Vendor βββ Invoice β β β β Hot Storage β β Warm Storage β β Cold ββ
β β Vendor βββ Contract β β β β (redb) β β (LanceDB) β βParquetββ
β β Invoice βββ LineItem β β β β < 30 days β β 30-365 days β β >365d ββ
β β Invoice βββ Contract β β β β Sub-ms β β < 10ms β β<100ms ββ
β β + RDF export (ext-rdf) β β β ββββββββββββββββ ββββββββββββββββ βββββββββ
β ββββββββββββββββββββββββββββββ β β βββββββββββββββββββββ ββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββ β β Anomaly Store β β Baseline Store ββ
β β β (redb, z-scores) β β (redb, rolling) ββ
β β βββββββββββββββββββββ ββββββββββββββββββββ
β ββββββββββββββββββββββββββββββββββββββββββββββ
β β
βββββββββββββββ¬ββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β QUERY & DETECTION TIER β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β Unified Query Engine ββ
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββ
β β β FQL Parser β β Vector Searchβ β Full-Text β β Query β ββ
β β β (custom) β β (HNSW/IVF) β β (Tantivy) β β Optimizer β ββ
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββ
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β Anomaly Detection Pipeline ββ
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββ
β β β Rule Engine ββ β Statistical ββ β Datalog ββ β Semantic β ββ
β β β (GoRules) β β Analyzer β β (Ascent) β β Analyzer β ββ
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββ
β β β β ββ
β β β βΌ ββ
β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β β β β Statistical Analysis β ββ
β β β β βββββββββββββ βββββββββββββ βββββββββββββ β ββ
β β β β β Z-Score β β Percentileβ β Trend β β ββ
β β β β β Detection β β Scoring β β Detection β β ββ
β β β β βββββββββββββ βββββββββββββ βββββββββββββ β ββ
β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β βββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β Pipeline Operations (FQL) ββ
β β VALIDATE β ANALYZE β ANALYZE BASELINE β CROSS_VALIDATE β AGGREGATE ββ
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β API GATEWAY β
β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ βββββββββββββββββββ
β β REST API β β gRPC Services β β GraphQL β β WebSocket ββ
β β (axum) β β (tonic) β β (async-graphqlβ β (real-time) ββ
β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ βββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Principle | Implementation |
|---|---|
| Zero-Copy Data Path | rkyv serialization, memory-mapped indices, arena allocation |
| Shared-Nothing Scaling | Partition by tenant/document-type, independent shard processing |
| Tiered Consistency | Strong for financial data (redb), eventual for analytics (LanceDB) |
| Graceful Degradation | Circuit breakers, fallback to cached results, async retry queues |
Fen supports horizontal scaling through an event-driven distributed architecture with sharded storage and multi-node coordination.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CONTROL PLANE β
β βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β Raft Coordinator β β Config Service β β Metadata Store β β
β β (openraft) β β (etcd sync) β β (shard assignments) β β
β βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββββββΌββββββββββββββββββββ
βΌ βΌ βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EVENT BUS (Kafka) β
β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ β
β β fen.document. β β fen.document. β β fen.anomaly. β β fen.baseline. β β
β β ingestion β β processed β β detected β β updates β β
β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β COMPUTE PLANE (Stateless) β
β βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β β Ingestion Workers β β Validation Workers β β Baseline Workers β β
β β (GPU for ML) β β (Rule Engine) β β (Stats Computation) β β
β βββββββββββββββββββββββ βββββββββββββββββββββββ βββββββββββββββββββββββββββ β
β βββββββββββββββββββββββ βββββββββββββββββββββββ β
β β Notification Svc β β Metrics Aggregator β βββ Real-time Reporting β
β β (WebSocket/Email) β β (Prometheus) β β
β βββββββββββββββββββββββ βββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DATA PLANE (Sharded) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Shard Manager β β
β β Consistent Hashing: hash(tenant_id || doc_type) % num_shards β β
β β 2PC Coordinator for cross-shard transactions β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Shard 0 β β Shard 1 β β Shard 2 β β Shard N β β
β β ββββββββββ β β ββββββββββ β β ββββββββββ β β ββββββββββ β β
β β β redb β β β β redb β β β β redb β β β β redb β β β
β β β (hot) β β β β (hot) β β β β (hot) β β β β (hot) β β β
β β ββββββββββ€ β β ββββββββββ€ β β ββββββββββ€ β β ββββββββββ€ β β
β β βLanceDB β β β βLanceDB β β β βLanceDB β β β βLanceDB β β β
β β β (warm) β β β β (warm) β β β β (warm) β β β β (warm) β β β
β β ββββββββββ β β ββββββββββ β β ββββββββββ β β ββββββββββ β β
β β 3x replicas β β 3x replicas β β 3x replicas β β 3x replicas β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Component | Description |
|---|---|
| Event Streaming | Kafka-based event bus with protobuf schemas for all domain events |
| Consistent Hashing | XXH3-based partition key routing for tenant/document-type sharding |
| Two-Phase Commit | ACID transactions across shards with automatic retry and recovery |
| Notification Hub | Multi-channel delivery (WebSocket, Email, Webhook) with tenant preferences |
| gRPC Services | Inter-node communication with connection pooling |
| Raft Consensus | Leader election and cluster membership (optional) |
Fen supports both standalone and distributed deployment:
# Standalone mode (default) - single node, no external dependencies
CLUSTER_MODE=standalone cargo run -p fen-api
# Distributed mode - requires Kafka and multiple nodes
CLUSTER_MODE=distributed \
KAFKA_BOOTSTRAP_SERVERS=localhost:9092 \
NUM_SHARDS=16 \
cargo run -p fen-api| Topic | Description |
|---|---|
fen.document.ingestion |
New document uploaded for processing |
fen.document.processed |
Document parsing and embedding complete |
fen.anomaly.detected |
Anomaly found during validation |
fen.baseline.updates |
Vendor baseline recalculated |
fen.metrics |
Real-time metrics for observability |
fen.alerts |
System alerts and notifications |
The notification system supports pluggable delivery channels:
| Provider | Mode | Use Case |
|---|---|---|
| WebSocket | Immediate | Real-time UI updates |
| Batched | Periodic digest reports | |
| Webhook | Async | External integrations |
Configure per-tenant notification preferences:
// Set tenant to receive WebSocket and Email notifications
hub.set_tenant_providers(tenant_id, vec!["websocket", "email"]);| Tier | Backend | Age | Latency | Use Case |
|---|---|---|---|---|
| Hot | redb | <30 days | P99 < 500us | Sub-ms key-value lookups, ACID transactions |
| Warm | LanceDB | 30-365 days | P99 < 10ms | Vector search, hybrid SQL queries |
| Cold | DataFusion + Parquet | >365 days | P99 < 100ms | Archived data, batch analytics |
Multi-layer detection with increasing latency/sophistication:
- Layer 1 - Structural Validation (us latency): GoRules Zen for math validation, format checks, range validation
- Layer 2 - Relational Constraints (us-ms latency): Ascent Datalog for invoice-contract matching, duplicate detection
- Layer 3 - Statistical Anomaly (ms latency): Real-time z-score analysis against vendor baselines with trend detection
- Layer 4 - Semantic Contradiction (10s of ms): NLI model for invoice terms vs contract clauses
The statistical analysis layer compares incoming invoices against historical vendor baselines:
- Z-Score Analysis: Flag invoices with amounts beyond configurable standard deviations from vendor mean
- Percentile Scoring: Determine where an invoice falls in the vendor's historical distribution
- Trend Detection: Identify increasing, decreasing, stable, or volatile spending patterns
- Seasonal Awareness: Optional month-of-year baseline patterns for seasonal vendors
- Rolling Windows: Configurable baseline windows (30, 90, 365 days)
Example Response:
{
"anomaly_type": "StatisticalOutlier",
"severity": "Medium",
"description": "Invoice amount $10000.00 is 6.2 standard deviations from vendor baseline (mean: $1050.00)",
"statistical_score": {
"z_score": 6.2,
"percentile": 99.8,
"trend": "Stable",
"is_outlier": true,
"baseline_mean": 1050.0,
"baseline_stddev": 145.0,
"sample_count": 47
}
}Fen includes a powerful SQL-like query language with extensions for vector similarity search, cross-table ZIP queries, and pipeline operations for validation and analysis.
| Feature | Description |
|---|---|
| SQL-like Syntax | SELECT, FROM, WHERE, ORDER BY, LIMIT, OFFSET |
| Vector Search | VECTOR_DISTANCE(embedding, :vector) for semantic similarity |
| Full-text Search | BM25_SCORE() and CONTAINS() for keyword search |
| ZIP Queries | Cross-table joins between invoices and contracts |
| Pipeline Operations | Post-query validation and analysis via |> syntax |
-- Basic query with filter
SELECT invoice_number, vendor_name, total_amount
FROM invoices
WHERE total_amount > 1000
ORDER BY invoice_date DESC
LIMIT 20
-- Semantic search for similar invoices
SELECT *, VECTOR_DISTANCE(embedding, :query_vector) AS similarity
FROM invoices
WHERE VECTOR_DISTANCE(embedding, :query_vector) < 0.3
ORDER BY similarity ASC
-- Cross-table analysis: find invoices exceeding contract limits
SELECT inv.invoice_number, inv.total_amount, con.title, con.total_value
FROM invoices inv
ZIP contracts con ON inv.vendor_name = con.party_name
WHERE inv.total_amount > con.total_value
-- Pipeline: query with statistical baseline analysis
SELECT * FROM invoices
WHERE vendor_name = 'Acme Corp'
|> ANALYZE BASELINE vendor_name WINDOW 90 DAYS THRESHOLD 2.0
|> VALIDATE WITH ('math_check')| Operation | Description |
|---|---|
VALIDATE |
Run structural validation rules |
ANALYZE |
Detect anomalies with optional analyzers |
ANALYZE BASELINE |
Statistical outlier detection against vendor baselines |
CROSS_VALIDATE |
Compare invoice fields against contract fields |
AGGREGATE |
Group and compute aggregate metrics |
See Query Language Reference for complete documentation.
- Rust 1.75+
- pdfium library (for PDF processing)
cargo build --releasecargo test --workspacecargo run -p fen-apidocker-compose up --build| Method | Path | Description |
|---|---|---|
POST |
/documents |
Upload PDF, returns parsed invoice |
GET |
/documents |
List all documents |
GET |
/documents/:id |
Get specific document |
POST |
/validate |
Validate documents for anomalies |
POST |
/query |
Execute hybrid query (SQL + vector) |
GET |
/health |
Health check |
| Variable | Default | Description |
|---|---|---|
BIND_ADDRESS |
0.0.0.0:3000 |
Server bind address |
DATABASE_PATH |
data/fen.redb |
Path to redb database |
RULES_PATH |
(none) | Path to GoRules decision file |
MAX_UPLOAD_SIZE |
52428800 |
Max upload size in bytes (50MB) |
RATE_LIMIT_RPS |
100 |
Requests per second limit |
RATE_LIMIT_BURST |
200 |
Burst capacity |
| Variable | Default | Description |
|---|---|---|
STATISTICAL_ENABLED |
true |
Enable statistical analysis |
STATISTICAL_ON_INGEST |
false |
Run analysis during document ingestion |
STATISTICAL_ON_VALIDATE |
true |
Run analysis during validation |
STATISTICAL_THRESHOLD |
2.0 |
Z-score threshold for outlier detection |
STATISTICAL_METRICS |
total_amount |
Comma-separated metrics to analyze |
STATISTICAL_WINDOW_DAYS |
90 |
Rolling window for baseline computation |
STATISTICAL_SEASONAL |
true |
Enable seasonal baseline awareness |
| Query Type | P50 Latency | P99 Latency | Throughput |
|---|---|---|---|
| Point lookup (hot) | 100us | 500us | 100K QPS/shard |
| Range scan (hot, 100 rows) | 500us | 2ms | 50K QPS/shard |
| Vector search (top-10) | 1ms | 5ms | 10K QPS/shard |
| Hybrid (filter + vector) | 2ms | 10ms | 5K QPS/shard |
| Full-text search | 5ms | 20ms | 5K QPS/shard |
- tokio - Async runtime
- axum - Web framework
- redb - Embedded ACID database (hot tier)
- lancedb - Vector database with SQL support (warm tier)
- pdfium-render - PDF text extraction
- ort - ONNX Runtime for ML inference
- zen-engine - GoRules decision engine
- arrow - Columnar data format