#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IndustrySchema {
pub required_fields: Vec<String>,
pub conventions: Vec<String>,
}
pub fn industry_schema_for(industry: &str) -> Option<IndustrySchema> {
match industry.to_lowercase().as_str() {
"housing" => Some(IndustrySchema {
required_fields: vec![
"personnummer".into(),
"queue_start_date".into(),
"annual_income".into(),
],
conventions: vec![
"Housing models track a personal identifier (personnummer in SE), a queue-start date, and an income declaration.".into(),
"Listings usually carry monthly_rent (in local currency minor units) and a boolean `is_active` for visibility.".into(),
],
}),
"healthcare" => Some(IndustrySchema {
required_fields: vec!["patient_id".into(), "created_at".into()],
conventions: vec![
"Patient identifiers should be opaque strings (UUID / hashed). Sequential integers leak enrolment order and are refused by the planner under this industry.".into(),
"Health records typically carry created_at, updated_at, and a soft-delete via deleted_at rather than physical removal.".into(),
],
}),
"banking" => Some(IndustrySchema {
required_fields: vec![
"account_number".into(),
"currency".into(),
"balance".into(),
],
conventions: vec![
"Monetary values are stored as integer minor units (öre, cents). Floating-point types are refused by the planner under this industry.".into(),
"Account numbers are stored as String; i32 has insufficient range for international account number formats.".into(),
],
}),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn housing_has_personnummer_as_a_required_field() {
let h = industry_schema_for("housing").unwrap();
assert!(h.required_fields.iter().any(|f| f == "personnummer"));
}
#[test]
fn case_insensitive_lookup() {
assert!(industry_schema_for("HEALTHCARE").is_some());
assert!(industry_schema_for("Healthcare").is_some());
}
#[test]
fn unknown_industry_returns_none() {
assert!(industry_schema_for("martian_postal_service").is_none());
}
}