Saltar al contenido principal

Arquitectura

Heldar es un plano de control HTTP ligero (rutas Axum) sobre un conjunto de servicios en segundo plano de larga duración, todos compartiendo un único almacén SQLite y una única configuración. El núcleo (heldar-kernel) es agnóstico al dominio: gestiona cámaras, ingesta y graba RTSP, muestrea fotogramas para IA, acepta detecciones de los trabajadores, evalúa zonas espaciales, y proporciona autenticación, retención y observabilidad. No sabe nada sobre control de acceso, inteligencia de movimiento o búsqueda; esas son aplicaciones.

Dos reglas dan forma a todo el sistema:

  • El núcleo es lo único que se comunica con las cámaras. El grabador continuo (24/7) copia el flujo de bits comprimido al disco sin decodificar. Un muestreador con presupuesto fijo es el único componente que decodifica, escribiendo un JPEG actual por cámara. Un trabajador de IA lento o ausente nunca puede bloquear la ingesta ni la grabación.
  • El núcleo no tiene dependencia de ninguna aplicación. Las aplicaciones dependen del núcleo y se enlazan mediante un binario compositor. Añadir una aplicación es una inserción en unos pocos puntos de composición, nunca una edición al núcleo.

Para el diseño completo por etapa (supervisor del grabador, indexador, barredor de retención, motor de zonas, métricas y más), consulte ARCHITECTURE.md en el repositorio.

Las cuatro juntas públicas

Las aplicaciones se conectan al núcleo únicamente a través de estas juntas. Juntas permiten que una nueva aplicación añada tablas, rutas, lógica de percepción y autorización sin que el núcleo la nombre en ningún momento.

1. El trait DetectionConsumer

Tras persistir un lote de detecciones de un trabajador, la ruta de ingesta del núcleo lo distribuye a un registro de consumidores. Un consumidor declara de forma autónoma qué task_types le interesan, por lo que el núcleo nunca acumula una rama if task_type == "...".

pub struct DetectionBatch<'a> {
pub camera_id: &'a str,
pub site_id: Option<&'a str>,
pub task_type: &'a str,
pub detections: &'a [DetectionIngest],
pub timestamp: DateTime<Utc>,
}

#[async_trait::async_trait]
pub trait DetectionConsumer: Send + Sync {
fn name(&self) -> &'static str;
fn interested_in(&self, task_type: &str) -> bool;
async fn consume(&self, batch: &DetectionBatch<'_>);
}

El motor de zonas abierto (una primitiva espacial) y el motor de control de acceso abierto (autorización de matrículas) son ambos consumidores. El motor de zonas devuelve true para cualquier tipo de tarea con detecciones rastreadas; el motor de control de acceso devuelve true solo para anpr.

2. Fusión de Router<AppState>

Cada aplicación expone su propio Router<AppState> de Axum con rutas absolutas /api/v1/.... El servidor compositor fusiona esos enrutadores junto al enrutador del núcleo; el enrutador del núcleo no los conoce. Desde AppState un manejador de aplicación accede al pool SQLite compartido, la configuración del núcleo, y el grabador/muestreador/cliente HTTP.

3. Esquema de autoinstalación

Cada aplicación posee sus propias tablas y aplica su esquema de forma idempotente contra el pool compartido al iniciar (un solo inquilino por despliegue). El núcleo no define tablas de dominio. El patrón es un schema::init(pool) que ejecuta un include_str! de un schema.sql lleno de CREATE TABLE IF NOT EXISTS.

4. La primitiva de autenticación

El núcleo proporciona un extractor Principal más comprobaciones de capacidad RBAC (can_view, can_manage_registry, can_operate_gate, entre otros) y un ayudante de auditoría. Las aplicaciones reutilizan estos elementos para autorización y auditoría en lugar de inventar los propios, de modo que un único interruptor HELDAR_AUTH_ENABLED gobierna toda la superficie compuesta.

Cómo se compone un despliegue

El servidor compositor (heldar-server) es donde el núcleo y un conjunto elegido de aplicaciones se integran. Para cada aplicación: aplica el esquema de la aplicación, construye los consumidores de detección de la aplicación y los añade al vector de consumidores en AppState, fusiona el enrutador de la aplicación, y lanza cualquier bucle en segundo plano bajo un supervisor que relanza en caso de pánico. La compilación de referencia abierta compone solo el núcleo más las aplicaciones genéricas Apache-2.0; un despliegue diferente enlaza un conjunto diferente de crates aquí.

No todas las aplicaciones son un DetectionConsumer. Algunas aplicaciones son bucles periódicos en segundo plano o capas de consulta de solo lectura sobre hechos del núcleo ya almacenados; utilizan la misma composición de esquema + enrutador + bucle sin situarse en la ruta caliente de ingesta.

Consulte Construir un módulo para un recorrido paso a paso sobre cómo escribir uno, y Open-core para el límite entre abierto y propietario.