Initial commit: content-driven onboarding portal

Leptos/Axum app that renders a Question/Alternative/Feature schema
loaded from a sibling content repo (portal-content). Kanidm OIDC login,
content-driven authorization (Question.qualifies), a generic NATS
KV-backed resource + state-transition mechanism (no bespoke "applicant"
concept baked into the runtime - it's all content), a SHA-256 DAG chain
tying submissions and decisions together, and the "YES - Rasterized
Lines" piece (ported from the live uhhm.no site) as the landing hero.
This commit is contained in:
Bendik Aagaard Lynghaug
2026-07-29 19:38:40 +02:00
commit aa1a7fa572
21 changed files with 7873 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
//! Plain NATS event publishing - ported from dodrenett's lib/nats.ts
//! (AnswerSubmitted). Deliberately just a publish, no stream/consumer
//! bookkeeping here: whoever reads `portal.answers.submitted` today is a
//! person watching the subject; a future LLM-driven follow-up poster
//! reads the exact same subject and shape, so this doesn't need to
//! change shape when that shows up, only gain a second subscriber.
#![cfg(feature = "ssr")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AnswerSubmitted {
pub chain_hash: String,
pub parent_hashes: Vec<String>,
pub question_id: String,
pub alternative: String,
pub responses: serde_json::Value,
pub timestamp_ms: i64,
}
pub const ANSWERS_SUBJECT: &str = "portal.answers.submitted";
pub async fn emit_answer_submitted(
nats: &async_nats::Client,
payload: &AnswerSubmitted,
) -> anyhow::Result<()> {
let data = serde_json::to_vec(payload)?;
nats.publish(ANSWERS_SUBJECT, data.into()).await?;
Ok(())
}