Oppgave-noder: proposal/assignment/task node_kind med validering

Tre nye node-typer for oppgavestyring:
- proposal: status (draft/discussed/approved/rejected/parked)
- assignment: status (open/planning/active/paused/done/blocked) + priority
- task: status (open/active/done/failed/skipped) + priority

Validering i create_node og update_node. Ingen ny tabell —
bruker eksisterende nodes-tabell med metadata.
Ref: docs/infra/oppgaver.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-20 01:37:32 +00:00
parent 68d8fff2dd
commit 494a6b5f18

View file

@ -317,6 +317,69 @@ fn validate_orchestration_metadata(
Ok(()) Ok(())
} }
/// Validerer metadata for oppgave-noder (proposal, assignment, task).
///
/// Ref: docs/infra/oppgaver.md
fn validate_task_metadata(
node_kind: &str,
metadata: &serde_json::Value,
) -> Result<(), String> {
match node_kind {
"proposal" => {
// Valgfri status, default "draft"
if let Some(status) = metadata.get("status").and_then(|v| v.as_str()) {
let valid = ["draft", "discussed", "approved", "rejected", "parked"];
if !valid.contains(&status) {
return Err(format!(
"proposal metadata.status må være en av: {}",
valid.join(", ")
));
}
}
Ok(())
}
"assignment" => {
// Valgfri status, default "open"
if let Some(status) = metadata.get("status").and_then(|v| v.as_str()) {
let valid = ["open", "planning", "active", "paused", "done", "blocked"];
if !valid.contains(&status) {
return Err(format!(
"assignment metadata.status må være en av: {}",
valid.join(", ")
));
}
}
// Valgfri priority (heltall)
if let Some(val) = metadata.get("priority") {
if !val.is_number() {
return Err("assignment metadata.priority må være et tall".into());
}
}
Ok(())
}
"task" => {
// Valgfri status, default "open"
if let Some(status) = metadata.get("status").and_then(|v| v.as_str()) {
let valid = ["open", "active", "done", "failed", "skipped"];
if !valid.contains(&status) {
return Err(format!(
"task metadata.status må være en av: {}",
valid.join(", ")
));
}
}
// Valgfri priority (heltall)
if let Some(val) = metadata.get("priority") {
if !val.is_number() {
return Err("task metadata.priority må være et tall".into());
}
}
Ok(())
}
_ => Ok(()),
}
}
#[derive(Serialize)] #[derive(Serialize)]
pub struct ErrorResponse { pub struct ErrorResponse {
pub error: String, pub error: String,
@ -649,6 +712,9 @@ pub async fn create_node(
// -- Valider metadata for orchestration-noder (oppgave 24.1) -- // -- Valider metadata for orchestration-noder (oppgave 24.1) --
validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?;
// -- Valider metadata for oppgave-noder (proposal/assignment/task) --
validate_task_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?;
// -- Kontekstbasert identitet (oppgave 8.2) -- // -- Kontekstbasert identitet (oppgave 8.2) --
// Hvis context_id er satt, sjekk om brukeren har et alias som er // Hvis context_id er satt, sjekk om brukeren har et alias som er
// deltaker i kommunikasjonsnoden. I så fall brukes aliaset som created_by. // deltaker i kommunikasjonsnoden. I så fall brukes aliaset som created_by.
@ -1186,6 +1252,9 @@ pub async fn update_node(
// -- Valider metadata for orchestration-noder (oppgave 24.1) -- // -- Valider metadata for orchestration-noder (oppgave 24.1) --
validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?; validate_orchestration_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?;
// -- Valider metadata for oppgave-noder --
validate_task_metadata(&node_kind, &metadata).map_err(|e| bad_request(&e))?;
// -- Beskytt model_profile for egendefinerte AI-presets (oppgave 18.6) -- // -- Beskytt model_profile for egendefinerte AI-presets (oppgave 18.6) --
// Kun admin/owner på en samling kan endre model_profile. Vanlige brukere // Kun admin/owner på en samling kan endre model_profile. Vanlige brukere
// som eier et custom preset kan redigere alt annet (prompt, icon, farge osv.) // som eier et custom preset kan redigere alt annet (prompt, icon, farge osv.)