Saltar al contenido principal
Version: Siguiente

Servicios de Infraestructura

Este documento describe los servicios de infraestructura compartidos que soportan los servicios de dominio en Lana Bank. Estos servicios proporcionan capacidades transversales como auditoría, autorización, publicación de eventos y trazabilidad.

Visión General de la Arquitectura

┌─────────────────────────────────────────────────────────────────┐
│ Servicios de Dominio │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │core-credit │ │core-deposit │ │core-customer│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│ Servicios de Infraestructura (lib/*) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ audit │ │ authz │ │ outbox │ │ job │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ ┌─────────────────┐ ┌─────────────────────────────┐ │
│ │ tracing-utils │ │ cloud-storage │ │
│ └─────────────────┘ └─────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Componentes Principales

Sistema de Auditoría (audit)

Proporciona registro inmutable de acciones para cumplimiento normativo y trazabilidad.

// lib/audit/src/lib.rs
pub struct AuditService {
pool: PgPool,
tracer: Tracer,
}

impl AuditService {
pub async fn record(
&self,
subject: &Subject,
action: Action,
object: Object,
outcome: Outcome,
) -> Result<AuditEntry, AuditError> {
let entry = AuditEntry {
id: AuditEntryId::new(),
subject_id: subject.id().to_string(),
subject_type: subject.subject_type(),
action: action.to_string(),
object_type: object.object_type(),
object_id: object.id().map(|id| id.to_string()),
outcome: outcome.to_string(),
metadata: serde_json::Value::Null,
trace_id: self.current_trace_id(),
created_at: Utc::now(),
};

self.persist(&entry).await?;
Ok(entry)
}
}

Estructura de Entrada de Auditoría

CampoTipoDescripción
idUUIDIdentificador único
subject_idStringID del actor (usuario/sistema)
subject_typeStringTipo de actor
actionStringAcción realizada
object_typeStringTipo de recurso afectado
object_idStringID del recurso
outcomeStringResultado (success/failure)
trace_idStringID de traza para correlación
created_atTimestampFecha y hora

Sistema de Autorización (authz)

Implementa Control de Acceso Basado en Roles (RBAC) usando Casbin.

// lib/authz/src/lib.rs
pub struct AuthzService {
enforcer: Arc<RwLock<Enforcer>>,
}

impl AuthzService {
pub async fn enforce(
&self,
subject: &Subject,
object: Object,
action: Action,
) -> Result<(), AuthzError> {
let enforcer = self.enforcer.read().await;

let allowed = enforcer.enforce((
subject.id().to_string(),
object.to_string(),
action.to_string(),
))?;

if !allowed {
return Err(AuthzError::PermissionDenied {
subject: subject.id().to_string(),
object: object.to_string(),
action: action.to_string(),
});
}

Ok(())
}

pub async fn add_role_for_user(
&self,
user_id: &str,
role: &str,
) -> Result<(), AuthzError> {
let mut enforcer = self.enforcer.write().await;
enforcer.add_role_for_user(user_id, role, None).await?;
Ok(())
}
}

Modelo Casbin


# model.conf

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

Publicación de Eventos (outbox)

Implementa el patrón outbox para entrega confiable de eventos.

// lib/outbox/src/lib.rs
pub struct OutboxPublisher {
pool: PgPool,
}

impl OutboxPublisher {
pub async fn publish<E: Serialize>(
&self,
event: &E,
db_op: &mut DbOp<'_>,
) -> Result<i64, OutboxError> {
let payload = serde_json::to_value(event)?;
let trace_context = TraceContext::from_current_span();

let sequence = sqlx::query_scalar!(
r#"
INSERT INTO outbox_events (event_type, payload, trace_context)
VALUES ($1, $2, $3)
RETURNING sequence
"#,
std::any::type_name::<E>(),
payload,
serde_json::to_value(&trace_context)?,
)
.fetch_one(db_op.as_mut())
.await?;

Ok(sequence)
}
}

Sistema de Trabajos (job)

Proporciona infraestructura para procesamiento de tareas en segundo plano.

// lib/job/src/lib.rs
pub trait Job: Send + Sync + 'static {
const NAME: &'static str;

async fn run(&self, current_job: CurrentJob) -> Result<JobCompletion, JobError>;
}

pub enum JobCompletion {
Complete,
RescheduleAt(DateTime<Utc>),
RescheduleIn(Duration),
}

pub struct JobRegistry {
jobs: HashMap<String, Arc<dyn Job>>,
}

impl JobRegistry {
pub fn register<J: Job>(&mut self, job: J) {
self.jobs.insert(J::NAME.to_string(), Arc::new(job));
}
}

Trazado y Observabilidad (tracing-utils)