1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum VaultLifecycle {
10 Unconfigured,
11 Locked,
12 Unlocked,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(rename_all = "snake_case")]
17pub enum NetworkExposure {
18 Offline,
19 LocalOnly,
20 ExternalCapable,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "snake_case")]
25pub enum SyncQueueState {
26 Idle,
27 Queued,
28 Sending,
29 Acknowledged,
30 Conflicted,
31 Rejected,
32 Revoked,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37pub enum SensitivityClassDto {
38 Public,
39 Restricted,
40 Classified,
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44pub struct AccessibilityPreferences {
45 pub high_contrast: bool,
46 pub reduced_motion: bool,
47 pub text_scale_percent: u8,
48 pub screen_reader_hints: bool,
49}
50
51impl Default for AccessibilityPreferences {
52 fn default() -> Self {
53 Self {
54 high_contrast: false,
55 reduced_motion: false,
56 text_scale_percent: 100,
57 screen_reader_hints: true,
58 }
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
63pub struct ProvenanceHop {
64 pub label: String,
65 pub evidence_type: String,
66 pub hash_prefix: String,
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70pub struct ConsentGrantDraft {
71 pub recipient: String,
72 pub purpose: String,
73 pub fields: Vec<String>,
74 pub expires_at_unix: Option<u64>,
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78#[serde(rename_all = "snake_case")]
79pub enum PolicyDecisionDto {
80 Permit {
81 obligations: Vec<String>,
82 },
83 Deny {
84 reasons: Vec<String>,
85 },
86 Prompt {
87 requested_consent: ConsentGrantDraft,
88 },
89 Suspend {
90 required_approvals: u8,
91 },
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
100#[serde(rename_all = "snake_case", tag = "outcome")]
101pub enum SubmitOutcome {
102 Committed { quins: usize },
103 Suspended { proposal_id: String, threshold: u8 },
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
108pub struct GuardianshipProposalView {
109 pub proposal_id: String,
110 pub principal_did: String,
111 pub proxy_did: String,
112 pub escrowed_kind: String,
113 pub reason: String,
114 pub created_unix: u32,
115 pub state: String,
117 pub approvals: u8,
118 pub threshold: u8,
119 pub denied_by: Option<String>,
120 pub denial_reason: Option<String>,
121 pub committed: bool,
123}
124
125impl GuardianshipProposalView {
126 pub fn from_status(
127 proposal: &wellfare_core::guardianship::GuardianshipProposal,
128 status: &wellfare_core::guardianship::ProposalStatus,
129 committed: bool,
130 ) -> Self {
131 use wellfare_core::guardianship::ProposalState;
132 let state = match status.state {
133 ProposalState::Pending => "pending",
134 ProposalState::Ratified => "ratified",
135 ProposalState::Denied => "denied",
136 }
137 .to_string();
138 Self {
139 proposal_id: proposal.id.clone(),
140 principal_did: proposal.principal_did.clone(),
141 proxy_did: proposal.proxy_did.clone(),
142 escrowed_kind: proposal.escrowed_kind.clone(),
143 reason: proposal.reason.clone(),
144 created_unix: proposal.created_unix,
145 state,
146 approvals: status.approvals,
147 threshold: status.threshold,
148 denied_by: status.denied_by.clone(),
149 denial_reason: status.denial_reason.clone(),
150 committed,
151 }
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
156pub struct WellfairHostSnapshot {
157 pub vault: VaultLifecycle,
158 pub network: NetworkExposure,
159 pub sync_state: SyncQueueState,
160 pub demo_mode: bool,
161 pub owner_label: String,
162 pub accessibility: AccessibilityPreferences,
163 pub pending_jobs: u32,
164 pub health_record_count: u32,
165 pub graph_quin_count: u32,
166 pub last_checkpoint_prefix: Option<String>,
167 pub capabilities_ready: bool,
168 pub host_api_version: String,
169}
170
171impl Default for WellfairHostSnapshot {
172 fn default() -> Self {
173 Self {
174 vault: VaultLifecycle::Unconfigured,
175 network: NetworkExposure::Offline,
176 sync_state: SyncQueueState::Idle,
177 demo_mode: false,
178 owner_label: String::new(),
179 accessibility: AccessibilityPreferences::default(),
180 pending_jobs: 0,
181 health_record_count: 0,
182 graph_quin_count: 0,
183 last_checkpoint_prefix: None,
184 capabilities_ready: false,
185 host_api_version: crate::qapp_install::SUPPORTED_HOST_API_VERSION.to_string(),
186 }
187 }
188}
189
190pub fn fixture_host_snapshot() -> WellfairHostSnapshot {
192 WellfairHostSnapshot {
193 vault: VaultLifecycle::Locked,
194 network: NetworkExposure::LocalOnly,
195 sync_state: SyncQueueState::Idle,
196 demo_mode: false,
197 owner_label: "Owner vault (fixture)".to_string(),
198 accessibility: AccessibilityPreferences::default(),
199 pending_jobs: 0,
200 health_record_count: 0,
201 graph_quin_count: 0,
202 last_checkpoint_prefix: None,
203 capabilities_ready: true,
204 host_api_version: crate::qapp_install::SUPPORTED_HOST_API_VERSION.to_string(),
205 }
206}
207
208pub fn demo_host_snapshot() -> WellfairHostSnapshot {
209 WellfairHostSnapshot {
210 vault: VaultLifecycle::Unlocked,
211 network: NetworkExposure::Offline,
212 sync_state: SyncQueueState::Idle,
213 demo_mode: true,
214 owner_label: "Demo persona (isolated)".to_string(),
215 ..WellfairHostSnapshot::default()
216 }
217}