decision_cockpit 0.1.0

Layer — product decision memory with MCP tools and an embedded review dashboard
Documentation
use axum::extract::State;
use axum::Json;
use serde::Deserialize;
use serde_json::Value;
use uuid::Uuid;

use crate::domain::relations::EntityRelation;
use crate::domain::{EntityType, RelationType};
use crate::error::{AppError, AppResult};
use crate::services::relations as svc;
use crate::state::AppState;

#[derive(Debug, Deserialize)]
pub struct CreateRelationBody {
    pub from_entity_id: Uuid,
    pub from_entity_type: String,
    pub to_entity_id: Uuid,
    pub to_entity_type: String,
    pub relation_type: String,
}

pub async fn create(
    State(state): State<AppState>,
    Json(body): Json<CreateRelationBody>,
) -> AppResult<Json<EntityRelation>> {
    let input = svc::NewRelationInput {
        from_entity_id: body.from_entity_id,
        from_entity_type: parse_entity_type(&body.from_entity_type)?,
        to_entity_id: body.to_entity_id,
        to_entity_type: parse_entity_type(&body.to_entity_type)?,
        relation_type: parse_relation_type(&body.relation_type)?,
    };
    let relation = svc::create_relation(&state.pool, input).await?;
    Ok(Json(relation))
}

fn parse_entity_type(s: &str) -> AppResult<EntityType> {
    serde_json::from_value::<EntityType>(Value::String(s.trim().to_string()))
        .map_err(|_| AppError::Validation(format!("unknown entity type `{s}`")))
}

fn parse_relation_type(s: &str) -> AppResult<RelationType> {
    serde_json::from_value::<RelationType>(Value::String(s.trim().to_string()))
        .map_err(|_| AppError::Validation(format!("unknown relation type `{s}`")))
}