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

- Go backend API with full CRUD for all modules
- Rust analytics service with parallel processing
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables
- Redis cache, Kafka event streaming
- WebSocket hub, automation engine
- PDF generation, Resend email integration
- JWT auth, multi-tenant
- Docker Compose deployment
- Nginx reverse proxy

Refs: BOC-001
This commit is contained in:
Bernt (LandveX AI)
2026-07-12 13:21:10 +00:00
commit 67a69ab073
1130 changed files with 18263 additions and 0 deletions
+167
View File
@@ -0,0 +1,167 @@
use axum::{
routing::{get, post},
Router,
Json,
extract::State,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{info, error};
mod analytics;
mod reports;
mod ipc;
use analytics::AnalyticsEngine;
use reports::ReportGenerator;
#[derive(Clone)]
struct AppState {
analytics: Arc<RwLock<AnalyticsEngine>>,
reports: Arc<RwLock<ReportGenerator>>,
}
#[derive(Serialize)]
struct HealthResponse {
status: String,
service: String,
version: String,
}
#[derive(Deserialize)]
struct ReportRequest {
tenant_id: String,
report_type: String,
parameters: serde_json::Value,
}
#[derive(Serialize)]
struct ReportResponse {
report_id: String,
status: String,
data: Option<serde_json::Value>,
}
#[derive(Deserialize)]
struct AnalyticsRequest {
tenant_id: String,
metric: String,
period: String,
}
#[derive(Serialize)]
struct AnalyticsResponse {
metric: String,
value: f64,
trend: f64,
breakdown: Vec<BreakdownItem>,
}
#[derive(Serialize)]
struct BreakdownItem {
label: String,
value: f64,
}
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_env_filter("boc_rust_service=info")
.init();
info!("BOC Rust Service starting...");
let state = AppState {
analytics: Arc::new(RwLock::new(AnalyticsEngine::new())),
reports: Arc::new(RwLock::new(ReportGenerator::new())),
};
let app = Router::new()
.route("/health", get(health_handler))
.route("/api/v1/reports/generate", post(generate_report))
.route("/api/v1/analytics/query", post(query_analytics))
.route("/api/v1/analytics/batch", post(batch_analytics))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:9093")
.await
.expect("Failed to bind port 9093");
info!("BOC Rust Service listening on 0.0.0.0:9093");
axum::serve(listener, app)
.await
.expect("Server failed");
}
async fn health_handler() -> Json<HealthResponse> {
Json(HealthResponse {
status: "ok".to_string(),
service: "boc-rust-service".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
})
}
async fn generate_report(
State(state): State<AppState>,
Json(req): Json<ReportRequest>,
) -> Json<ReportResponse> {
info!("Generating report: {} for tenant: {}", req.report_type, req.tenant_id);
let reports = state.reports.read().await;
match reports.generate(&req.tenant_id, &req.report_type, &req.parameters).await {
Ok(data) => Json(ReportResponse {
report_id: uuid::Uuid::new_v4().to_string(),
status: "completed".to_string(),
data: Some(data),
}),
Err(e) => {
error!("Report generation failed: {}", e);
Json(ReportResponse {
report_id: uuid::Uuid::new_v4().to_string(),
status: "failed".to_string(),
data: None,
})
}
}
}
async fn query_analytics(
State(state): State<AppState>,
Json(req): Json<AnalyticsRequest>,
) -> Json<AnalyticsResponse> {
let analytics = state.analytics.read().await;
let result = analytics.query(&req.tenant_id, &req.metric, &req.period).await;
Json(AnalyticsResponse {
metric: req.metric,
value: result.value,
trend: result.trend,
breakdown: result.breakdown.into_iter()
.map(|(label, value)| BreakdownItem { label, value })
.collect(),
})
}
async fn batch_analytics(
State(state): State<AppState>,
Json(reqs): Json<Vec<AnalyticsRequest>>,
) -> Json<Vec<AnalyticsResponse>> {
let analytics = state.analytics.read().await;
let mut responses = Vec::with_capacity(reqs.len());
for req in reqs {
let result = analytics.query(&req.tenant_id, &req.metric, &req.period).await;
responses.push(AnalyticsResponse {
metric: req.metric.clone(),
value: result.value,
trend: result.trend,
breakdown: result.breakdown.into_iter()
.map(|(label, value)| BreakdownItem { label, value })
.collect(),
});
}
Json(responses)
}