add heroledger models

This commit is contained in:
Timur Gordon 2025-08-05 12:53:24 +02:00
parent 7d9a6906c6
commit 1a62fcacdd
12 changed files with 2240 additions and 318 deletions

View File

@ -1,318 +0,0 @@
# Payment Model Usage Guide
This document provides comprehensive instructions for AI assistants on how to use the Payment model in the heromodels repository.
## Overview
The Payment model represents a payment transaction in the system, typically associated with company registration or subscription payments. It integrates with Stripe for payment processing and maintains comprehensive status tracking.
## Model Structure
```rust
pub struct Payment {
pub base_data: BaseModelData, // Auto-managed ID, timestamps, comments
pub payment_intent_id: String, // Stripe payment intent ID
pub company_id: u32, // Foreign key to Company
pub payment_plan: String, // "monthly", "yearly", "two_year"
pub setup_fee: f64, // One-time setup fee
pub monthly_fee: f64, // Recurring monthly fee
pub total_amount: f64, // Total amount paid
pub currency: String, // Currency code (defaults to "usd")
pub status: PaymentStatus, // Current payment status
pub stripe_customer_id: Option<String>, // Stripe customer ID (set on completion)
pub created_at: i64, // Payment creation timestamp
pub completed_at: Option<i64>, // Payment completion timestamp
}
pub enum PaymentStatus {
Pending, // Initial state - payment created but not processed
Processing, // Payment is being processed by Stripe
Completed, // Payment successfully completed
Failed, // Payment processing failed
Refunded, // Payment was refunded
}
```
## Basic Usage
### 1. Creating a New Payment
```rust
use heromodels::models::biz::{Payment, PaymentStatus};
// Create a new payment with required fields
let payment = Payment::new(
"pi_1234567890".to_string(), // Stripe payment intent ID
company_id, // Company ID from database
"monthly".to_string(), // Payment plan
100.0, // Setup fee
49.99, // Monthly fee
149.99, // Total amount
);
// Payment defaults:
// - status: PaymentStatus::Pending
// - currency: "usd"
// - stripe_customer_id: None
// - created_at: current timestamp
// - completed_at: None
```
### 2. Using Builder Pattern
```rust
let payment = Payment::new(
"pi_1234567890".to_string(),
company_id,
"yearly".to_string(),
500.0,
99.99,
1699.88,
)
.currency("eur".to_string())
.stripe_customer_id(Some("cus_existing_customer".to_string()));
```
### 3. Database Operations
```rust
use heromodels::db::Collection;
// Save payment to database
let db = get_db()?;
let (payment_id, saved_payment) = db.set(&payment)?;
// Retrieve payment by ID
let retrieved_payment: Payment = db.get_by_id(payment_id)?.unwrap();
// Update payment
let updated_payment = saved_payment.complete_payment(Some("cus_new_customer".to_string()));
let (_, final_payment) = db.set(&updated_payment)?;
```
## Payment Status Management
### Status Transitions
```rust
// 1. Start with Pending status (default)
let payment = Payment::new(/* ... */);
assert!(payment.is_pending());
// 2. Mark as processing when Stripe starts processing
let processing_payment = payment.process_payment();
assert!(processing_payment.is_processing());
// 3. Complete payment when Stripe confirms success
let completed_payment = processing_payment.complete_payment(Some("cus_123".to_string()));
assert!(completed_payment.is_completed());
assert!(completed_payment.completed_at.is_some());
// 4. Handle failure if payment fails
let failed_payment = processing_payment.fail_payment();
assert!(failed_payment.has_failed());
// 5. Refund if needed
let refunded_payment = completed_payment.refund_payment();
assert!(refunded_payment.is_refunded());
```
### Status Check Methods
```rust
// Check current status
if payment.is_pending() {
// Show "Payment Pending" UI
} else if payment.is_processing() {
// Show "Processing Payment" UI
} else if payment.is_completed() {
// Show "Payment Successful" UI
// Enable company features
} else if payment.has_failed() {
// Show "Payment Failed" UI
// Offer retry option
} else if payment.is_refunded() {
// Show "Payment Refunded" UI
}
```
## Integration with Company Model
### Complete Payment Flow
```rust
use heromodels::models::biz::{Company, CompanyStatus, Payment, PaymentStatus};
// 1. Create company with pending payment status
let company = Company::new(
"TechStart Inc.".to_string(),
"REG-TS-2024-001".to_string(),
chrono::Utc::now().timestamp(),
)
.email("contact@techstart.com".to_string())
.status(CompanyStatus::PendingPayment);
let (company_id, company) = db.set(&company)?;
// 2. Create payment for the company
let payment = Payment::new(
stripe_payment_intent_id,
company_id,
"yearly".to_string(),
500.0, // Setup fee
99.0, // Monthly fee
1688.0, // Total (setup + 12 months)
);
let (payment_id, payment) = db.set(&payment)?;
// 3. Process payment through Stripe
let processing_payment = payment.process_payment();
let (_, processing_payment) = db.set(&processing_payment)?;
// 4. On successful Stripe webhook
let completed_payment = processing_payment.complete_payment(Some(stripe_customer_id));
let (_, completed_payment) = db.set(&completed_payment)?;
// 5. Activate company
let active_company = company.status(CompanyStatus::Active);
let (_, active_company) = db.set(&active_company)?;
```
## Database Indexing
The Payment model provides custom indexes for efficient querying:
```rust
// Indexed fields for fast lookups:
// - payment_intent_id: Find payment by Stripe intent ID
// - company_id: Find all payments for a company
// - status: Find payments by status
// Example queries (conceptual - actual implementation depends on your query layer)
// let pending_payments = db.find_by_index("status", "Pending")?;
// let company_payments = db.find_by_index("company_id", company_id.to_string())?;
// let stripe_payment = db.find_by_index("payment_intent_id", "pi_1234567890")?;
```
## Error Handling Best Practices
```rust
use heromodels::db::DbError;
fn process_payment_flow(payment_intent_id: String, company_id: u32) -> Result<Payment, DbError> {
let db = get_db()?;
// Create payment
let payment = Payment::new(
payment_intent_id,
company_id,
"monthly".to_string(),
100.0,
49.99,
149.99,
);
// Save to database
let (payment_id, payment) = db.set(&payment)?;
// Process through Stripe (external API call)
match process_stripe_payment(&payment.payment_intent_id) {
Ok(stripe_customer_id) => {
// Success: complete payment
let completed_payment = payment.complete_payment(Some(stripe_customer_id));
let (_, final_payment) = db.set(&completed_payment)?;
Ok(final_payment)
}
Err(_) => {
// Failure: mark as failed
let failed_payment = payment.fail_payment();
let (_, final_payment) = db.set(&failed_payment)?;
Ok(final_payment)
}
}
}
```
## Testing
The Payment model includes comprehensive tests in `tests/payment.rs`. When working with payments:
1. **Always test status transitions**
2. **Verify timestamp handling**
3. **Test database persistence**
4. **Test integration with Company model**
5. **Test builder pattern methods**
```bash
# Run payment tests
cargo test payment
# Run specific test
cargo test test_payment_completion
```
## Common Patterns
### 1. Payment Retry Logic
```rust
fn retry_failed_payment(payment: Payment) -> Payment {
if payment.has_failed() {
// Reset to pending for retry
Payment::new(
payment.payment_intent_id,
payment.company_id,
payment.payment_plan,
payment.setup_fee,
payment.monthly_fee,
payment.total_amount,
)
.currency(payment.currency)
} else {
payment
}
}
```
### 2. Payment Summary
```rust
fn get_payment_summary(payment: &Payment) -> String {
format!(
"Payment {} for company {}: {} {} ({})",
payment.payment_intent_id,
payment.company_id,
payment.total_amount,
payment.currency.to_uppercase(),
payment.status
)
}
```
### 3. Payment Validation
```rust
fn validate_payment(payment: &Payment) -> Result<(), String> {
if payment.total_amount <= 0.0 {
return Err("Total amount must be positive".to_string());
}
if payment.payment_intent_id.is_empty() {
return Err("Payment intent ID is required".to_string());
}
if payment.company_id == 0 {
return Err("Valid company ID is required".to_string());
}
Ok(())
}
```
## Key Points for AI Assistants
1. **Always use auto-generated IDs** - Don't manually set IDs, let OurDB handle them
2. **Follow status flow** - Pending → Processing → Completed/Failed → (optionally) Refunded
3. **Update timestamps** - `completed_at` is automatically set when calling `complete_payment()`
4. **Use builder pattern** - For optional fields and cleaner code
5. **Test thoroughly** - Payment logic is critical, always verify with tests
6. **Handle errors gracefully** - Payment failures should be tracked, not ignored
7. **Integrate with Company** - Payments typically affect company status
8. **Use proper indexing** - Leverage indexed fields for efficient queries
This model follows the heromodels patterns and integrates seamlessly with the existing codebase architecture.

View File

@ -0,0 +1,301 @@
# AI Prompt: Convert V Language Specs to Rust Hero Models
## Objective
Convert V language model specifications (`.v` files) to Rust hero models that integrate with the heromodels framework. The generated Rust models should follow the established patterns for base data embedding, indexing, fluent builder APIs, and Rhai scripting integration.
## V Language Input Structure Analysis
### V Spec Patterns to Recognize:
1. **Module Declaration**: `module circle` or `module group`
2. **Base Embedding**: `core.Base` - represents the base model data
3. **Index Fields**: Fields marked with `@[index]` comments
4. **Mutability**: Fields declared with `pub mut:`
5. **Enums**: `pub enum Status { active, inactive, suspended }`
6. **Nested Structs**: Embedded configuration or related data structures
7. **Collections**: `[]u32`, `[]string`, `map[string]string`
8. **References**: `u32` fields typically represent foreign key references
### Example V Spec Structure:
```v
module circle
import freeflowuniverse.herolib.hero.models.core
pub struct User {
core.Base
pub mut:
username string @[index] // Unique username
email []string @[index] // Multiple email addresses
status UserStatus // Enum reference
profile UserProfile // Nested struct
metadata map[string]string // Key-value pairs
}
pub enum UserStatus {
active
inactive
suspended
}
pub struct UserProfile {
pub mut:
full_name string
bio string
links map[string]string
}
```
## Rust Hero Model Conversion Rules
### 1. File Structure and Imports
```rust
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use rhai::CustomType;
use rhailib_derive::RhaiApi;
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};
```
### 2. Base Data Embedding
- **V**: `core.Base`
- **Rust**: `pub base_data: BaseModelData,`
### 3. Index Field Conversion
- **V**: `field_name string @[index]`
- **Rust**: `#[index] pub field_name: String,`
### 4. Type Mappings
| V Type | Rust Type |
|--------|-----------|
| `string` | `String` |
| `[]string` | `Vec<String>` |
| `[]u32` | `Vec<u32>` |
| `u32` | `u32` |
| `u64` | `u64` |
| `f64` | `f64` |
| `bool` | `bool` |
| `map[string]string` | `std::collections::HashMap<String, String>` |
### 5. Struct Declaration Pattern
```rust
/// Documentation comment describing the model
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CustomType, Default, RhaiApi)]
pub struct ModelName {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub indexed_field: String,
pub regular_field: String,
pub optional_field: Option<String>,
pub nested_struct: NestedType,
pub collection: Vec<u32>,
pub metadata: std::collections::HashMap<String, String>,
}
```
### 6. Enum Conversion
```rust
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum UserStatus {
Active,
Inactive,
Suspended,
}
```
### 7. Fluent Builder Implementation
Every model must implement a fluent builder pattern:
```rust
impl ModelName {
/// Create a new instance
pub fn new(id: u32) -> Self {
Self {
base_data: BaseModelData::new(id),
indexed_field: String::new(),
regular_field: String::new(),
optional_field: None,
nested_struct: NestedType::new(),
collection: Vec::new(),
metadata: std::collections::HashMap::new(),
}
}
/// Set indexed field (fluent)
pub fn indexed_field(mut self, value: impl ToString) -> Self {
self.indexed_field = value.to_string();
self
}
/// Set regular field (fluent)
pub fn regular_field(mut self, value: impl ToString) -> Self {
self.regular_field = value.to_string();
self
}
/// Set optional field (fluent)
pub fn optional_field(mut self, value: impl ToString) -> Self {
self.optional_field = Some(value.to_string());
self
}
/// Set nested struct (fluent)
pub fn nested_struct(mut self, value: NestedType) -> Self {
self.nested_struct = value;
self
}
/// Add to collection (fluent)
pub fn add_to_collection(mut self, value: u32) -> Self {
self.collection.push(value);
self
}
/// Set entire collection (fluent)
pub fn collection(mut self, value: Vec<u32>) -> Self {
self.collection = value;
self
}
/// Add metadata entry (fluent)
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
/// Build the final instance
pub fn build(self) -> Self {
self
}
}
```
### 8. Model Trait Implementation
```rust
impl Model for ModelName {
fn db_prefix() -> &'static str {
"modelname"
}
fn get_id(&self) -> u32 {
self.base_data.id
}
fn base_data_mut(&mut self) -> &mut BaseModelData {
&mut self.base_data
}
fn db_keys(&self) -> Vec<IndexKey> {
let mut keys = Vec::new();
// Add index keys for fields marked with #[index]
keys.push(IndexKey::new("indexed_field", &self.indexed_field));
// Add additional index keys as needed
keys
}
}
```
### 9. Nested Struct Builder Pattern
For embedded types, implement similar builder patterns:
```rust
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct NestedType {
pub field1: String,
pub field2: String,
}
impl NestedType {
pub fn new() -> Self {
Self {
field1: String::new(),
field2: String::new(),
}
}
pub fn field1(mut self, value: impl ToString) -> Self {
self.field1 = value.to_string();
self
}
pub fn field2(mut self, value: impl ToString) -> Self {
self.field2 = value.to_string();
self
}
pub fn build(self) -> Self {
self
}
}
```
## Conversion Steps
1. **Analyze V Spec Structure**
- Identify the module name and main structs
- Note which fields are marked with `@[index]`
- Identify nested structs and enums
- Map field types from V to Rust
2. **Create Rust File Structure**
- Add appropriate imports
- Convert enums first (they're often referenced by structs)
- Convert nested structs before main structs
3. **Implement Main Struct**
- Add `#[model]` macro and derives
- Embed `BaseModelData` as `base_data`
- Mark indexed fields with `#[index]`
- Convert field types according to mapping table
4. **Implement Builder Pattern**
- Add `new(id: u32)` constructor
- Add fluent setter methods for each field
- Handle optional fields appropriately
- Add collection manipulation methods
5. **Implement Model Trait**
- Define appropriate `db_prefix`
- Implement required trait methods
- Add index keys for searchable fields
6. **Add Documentation**
- Document the struct and its purpose
- Document each field's meaning
- Add usage examples in comments
## Example Usage After Conversion
```rust
let user = User::new(1)
.username("john_doe")
.add_email("john@example.com")
.add_email("john.doe@company.com")
.status(UserStatus::Active)
.profile(
UserProfile::new()
.full_name("John Doe")
.bio("Software developer")
.build()
)
.add_metadata("department", "engineering")
.build();
```
## Notes and Best Practices
1. **Field Naming**: Convert V snake_case to Rust snake_case (usually no change needed)
2. **Optional Fields**: Use `Option<T>` for fields that may be empty in V
3. **Collections**: Always provide both `add_item` and `set_collection` methods
4. **Error Handling**: Builder methods should not panic; use appropriate defaults
5. **Documentation**: Include comprehensive documentation for public APIs
6. **Testing**: Consider adding unit tests for builder patterns
7. **Validation**: Add validation logic in builder methods if needed
## File Organization
Place the converted Rust models in the appropriate subdirectory under `heromodels/src/models/` based on the domain (e.g., `user/`, `finance/`, `governance/`, etc.).

View File

@ -0,0 +1,301 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Defines the supported DNS record types
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NameType {
A,
AAAA,
CNAME,
MX,
TXT,
SRV,
PTR,
NS,
}
impl Default for NameType {
fn default() -> Self {
NameType::A
}
}
/// Category of the DNS record
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NameCat {
IPv4,
IPv6,
Mycelium,
}
impl Default for NameCat {
fn default() -> Self {
NameCat::IPv4
}
}
/// Status of a DNS zone
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DNSZoneStatus {
Active,
Suspended,
Archived,
}
impl Default for DNSZoneStatus {
fn default() -> Self {
DNSZoneStatus::Active
}
}
/// Represents a DNS record configuration
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DNSRecord {
pub subdomain: String,
pub record_type: NameType,
pub value: String,
pub priority: u32,
pub ttl: u32,
pub is_active: bool,
pub cat: NameCat,
pub is_wildcard: bool,
}
impl DNSRecord {
pub fn new() -> Self {
Self {
subdomain: String::new(),
record_type: NameType::default(),
value: String::new(),
priority: 0,
ttl: 3600,
is_active: true,
cat: NameCat::default(),
is_wildcard: false,
}
}
pub fn subdomain(mut self, subdomain: impl ToString) -> Self {
self.subdomain = subdomain.to_string();
self
}
pub fn record_type(mut self, record_type: NameType) -> Self {
self.record_type = record_type;
self
}
pub fn value(mut self, value: impl ToString) -> Self {
self.value = value.to_string();
self
}
pub fn priority(mut self, priority: u32) -> Self {
self.priority = priority;
self
}
pub fn ttl(mut self, ttl: u32) -> Self {
self.ttl = ttl;
self
}
pub fn is_active(mut self, is_active: bool) -> Self {
self.is_active = is_active;
self
}
pub fn cat(mut self, cat: NameCat) -> Self {
self.cat = cat;
self
}
pub fn is_wildcard(mut self, is_wildcard: bool) -> Self {
self.is_wildcard = is_wildcard;
self
}
pub fn build(self) -> Self {
self
}
}
/// SOA (Start of Authority) record for a DNS zone
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SOARecord {
pub zone_id: u32,
pub primary_ns: String,
pub admin_email: String,
pub serial: u64,
pub refresh: u32,
pub retry: u32,
pub expire: u32,
pub minimum_ttl: u32,
pub is_active: bool,
}
impl SOARecord {
pub fn new() -> Self {
Self {
zone_id: 0,
primary_ns: String::new(),
admin_email: String::new(),
serial: 0,
refresh: 3600,
retry: 600,
expire: 604800,
minimum_ttl: 3600,
is_active: true,
}
}
pub fn zone_id(mut self, zone_id: u32) -> Self {
self.zone_id = zone_id;
self
}
pub fn primary_ns(mut self, primary_ns: impl ToString) -> Self {
self.primary_ns = primary_ns.to_string();
self
}
pub fn admin_email(mut self, admin_email: impl ToString) -> Self {
self.admin_email = admin_email.to_string();
self
}
pub fn serial(mut self, serial: u64) -> Self {
self.serial = serial;
self
}
pub fn refresh(mut self, refresh: u32) -> Self {
self.refresh = refresh;
self
}
pub fn retry(mut self, retry: u32) -> Self {
self.retry = retry;
self
}
pub fn expire(mut self, expire: u32) -> Self {
self.expire = expire;
self
}
pub fn minimum_ttl(mut self, minimum_ttl: u32) -> Self {
self.minimum_ttl = minimum_ttl;
self
}
pub fn is_active(mut self, is_active: bool) -> Self {
self.is_active = is_active;
self
}
pub fn build(self) -> Self {
self
}
}
/// Represents a DNS zone with its configuration and records
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct DNSZone {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub domain: String,
pub dnsrecords: Vec<DNSRecord>,
pub administrators: Vec<u32>,
pub status: DNSZoneStatus,
pub metadata: HashMap<String, String>,
pub soarecord: Vec<SOARecord>,
}
impl DNSZone {
/// Create a new DNS zone instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
domain: String::new(),
dnsrecords: Vec::new(),
administrators: Vec::new(),
status: DNSZoneStatus::default(),
metadata: HashMap::new(),
soarecord: Vec::new(),
}
}
/// Set the domain name (fluent)
pub fn domain(mut self, domain: impl ToString) -> Self {
self.domain = domain.to_string();
self
}
/// Add a DNS record (fluent)
pub fn add_dnsrecord(mut self, record: DNSRecord) -> Self {
self.dnsrecords.push(record);
self
}
/// Set all DNS records (fluent)
pub fn dnsrecords(mut self, dnsrecords: Vec<DNSRecord>) -> Self {
self.dnsrecords = dnsrecords;
self
}
/// Add an administrator (fluent)
pub fn add_administrator(mut self, admin_id: u32) -> Self {
self.administrators.push(admin_id);
self
}
/// Set all administrators (fluent)
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
self.administrators = administrators;
self
}
/// Set the zone status (fluent)
pub fn status(mut self, status: DNSZoneStatus) -> Self {
self.status = status;
self
}
/// Add metadata entry (fluent)
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
/// Set all metadata (fluent)
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
self.metadata = metadata;
self
}
/// Add an SOA record (fluent)
pub fn add_soarecord(mut self, soa: SOARecord) -> Self {
self.soarecord.push(soa);
self
}
/// Set all SOA records (fluent)
pub fn soarecord(mut self, soarecord: Vec<SOARecord>) -> Self {
self.soarecord = soarecord;
self
}
/// Build the final DNS zone instance
pub fn build(self) -> Self {
self
}
}

View File

@ -0,0 +1,236 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
/// Defines the lifecycle of a group
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum GroupStatus {
Active,
Inactive,
Suspended,
Archived,
}
impl Default for GroupStatus {
fn default() -> Self {
GroupStatus::Active
}
}
/// Visibility controls who can discover or view the group
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Visibility {
Public, // Anyone can see and request to join
Private, // Only invited users can see the group
Unlisted, // Not visible in search; only accessible by direct link or DNS
}
impl Default for Visibility {
fn default() -> Self {
Visibility::Public
}
}
/// GroupConfig holds rules that govern group membership and behavior
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct GroupConfig {
pub max_members: u32,
pub allow_guests: bool,
pub auto_approve: bool,
pub require_invite: bool,
}
impl GroupConfig {
pub fn new() -> Self {
Self {
max_members: 0,
allow_guests: false,
auto_approve: false,
require_invite: false,
}
}
pub fn max_members(mut self, max_members: u32) -> Self {
self.max_members = max_members;
self
}
pub fn allow_guests(mut self, allow_guests: bool) -> Self {
self.allow_guests = allow_guests;
self
}
pub fn auto_approve(mut self, auto_approve: bool) -> Self {
self.auto_approve = auto_approve;
self
}
pub fn require_invite(mut self, require_invite: bool) -> Self {
self.require_invite = require_invite;
self
}
pub fn build(self) -> Self {
self
}
}
/// Represents a collaborative or access-controlled unit within the system
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Group {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub name: String,
pub description: String,
pub dnsrecords: Vec<u32>,
pub administrators: Vec<u32>,
pub config: GroupConfig,
pub status: GroupStatus,
pub visibility: Visibility,
pub created: u64,
pub updated: u64,
}
impl Group {
/// Create a new group instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
name: String::new(),
description: String::new(),
dnsrecords: Vec::new(),
administrators: Vec::new(),
config: GroupConfig::new(),
status: GroupStatus::default(),
visibility: Visibility::default(),
created: 0,
updated: 0,
}
}
/// Set the group name (fluent)
pub fn name(mut self, name: impl ToString) -> Self {
self.name = name.to_string();
self
}
/// Set the group description (fluent)
pub fn description(mut self, description: impl ToString) -> Self {
self.description = description.to_string();
self
}
/// Add a DNS record ID (fluent)
pub fn add_dnsrecord(mut self, dnsrecord_id: u32) -> Self {
self.dnsrecords.push(dnsrecord_id);
self
}
/// Set all DNS record IDs (fluent)
pub fn dnsrecords(mut self, dnsrecords: Vec<u32>) -> Self {
self.dnsrecords = dnsrecords;
self
}
/// Add an administrator user ID (fluent)
pub fn add_administrator(mut self, user_id: u32) -> Self {
self.administrators.push(user_id);
self
}
/// Set all administrator user IDs (fluent)
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
self.administrators = administrators;
self
}
/// Set the group configuration (fluent)
pub fn config(mut self, config: GroupConfig) -> Self {
self.config = config;
self
}
/// Set the group status (fluent)
pub fn status(mut self, status: GroupStatus) -> Self {
self.status = status;
self
}
/// Set the group visibility (fluent)
pub fn visibility(mut self, visibility: Visibility) -> Self {
self.visibility = visibility;
self
}
/// Set the created timestamp (fluent)
pub fn created(mut self, created: u64) -> Self {
self.created = created;
self
}
/// Set the updated timestamp (fluent)
pub fn updated(mut self, updated: u64) -> Self {
self.updated = updated;
self
}
/// Build the final group instance
pub fn build(self) -> Self {
self
}
}
/// Represents the membership relationship between users and groups
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct UserGroupMembership {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub user_id: u32,
pub group_ids: Vec<u32>,
}
impl UserGroupMembership {
/// Create a new user group membership instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
user_id: 0,
group_ids: Vec::new(),
}
}
/// Set the user ID (fluent)
pub fn user_id(mut self, user_id: u32) -> Self {
self.user_id = user_id;
self
}
/// Add a group ID (fluent)
pub fn add_group_id(mut self, group_id: u32) -> Self {
self.group_ids.push(group_id);
self
}
/// Set all group IDs (fluent)
pub fn group_ids(mut self, group_ids: Vec<u32>) -> Self {
self.group_ids = group_ids;
self
}
/// Build the final membership instance
pub fn build(self) -> Self {
self
}
}

View File

@ -0,0 +1,115 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
/// Defines the possible roles a member can have
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MemberRole {
Owner,
Admin,
Moderator,
Member,
Guest,
}
impl Default for MemberRole {
fn default() -> Self {
MemberRole::Member
}
}
/// Represents the current status of membership
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum MemberStatus {
Active,
Pending,
Suspended,
Removed,
}
impl Default for MemberStatus {
fn default() -> Self {
MemberStatus::Pending
}
}
/// Represents a member within a circle
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Member {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub user_id: u32,
pub role: MemberRole,
pub status: MemberStatus,
pub joined_at: u64,
pub invited_by: u32,
pub permissions: Vec<String>,
}
impl Member {
/// Create a new member instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
user_id: 0,
role: MemberRole::default(),
status: MemberStatus::default(),
joined_at: 0,
invited_by: 0,
permissions: Vec::new(),
}
}
/// Set the user ID (fluent)
pub fn user_id(mut self, user_id: u32) -> Self {
self.user_id = user_id;
self
}
/// Set the member role (fluent)
pub fn role(mut self, role: MemberRole) -> Self {
self.role = role;
self
}
/// Set the member status (fluent)
pub fn status(mut self, status: MemberStatus) -> Self {
self.status = status;
self
}
/// Set the joined timestamp (fluent)
pub fn joined_at(mut self, joined_at: u64) -> Self {
self.joined_at = joined_at;
self
}
/// Set who invited this member (fluent)
pub fn invited_by(mut self, invited_by: u32) -> Self {
self.invited_by = invited_by;
self
}
/// Add a permission (fluent)
pub fn add_permission(mut self, permission: impl ToString) -> Self {
self.permissions.push(permission.to_string());
self
}
/// Set all permissions (fluent)
pub fn permissions(mut self, permissions: Vec<String>) -> Self {
self.permissions = permissions;
self
}
/// Build the final member instance
pub fn build(self) -> Self {
self
}
}

View File

@ -0,0 +1,19 @@
// Export all heroledger model modules
pub mod user;
pub mod group;
pub mod money;
pub mod membership;
pub mod dnsrecord;
pub mod secretbox;
pub mod signature;
pub mod user_kvs;
// Re-export key types for convenience
pub use user::{User, UserStatus, UserProfile, KYCInfo, KYCStatus, SecretBox};
pub use group::{Group, UserGroupMembership, GroupStatus, Visibility, GroupConfig};
pub use money::{Account, Asset, AccountPolicy, AccountPolicyItem, Transaction, AccountStatus, TransactionType, Signature as TransactionSignature};
pub use membership::{Member, MemberRole, MemberStatus};
pub use dnsrecord::{DNSZone, DNSRecord, SOARecord, NameType, NameCat, DNSZoneStatus};
pub use secretbox::{Notary, NotaryStatus, SecretBoxCategory};
pub use signature::{Signature, SignatureStatus, ObjectType};
pub use user_kvs::{UserKVS, UserKVSItem};

View File

@ -0,0 +1,515 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Represents the status of an account
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum AccountStatus {
Active,
Inactive,
Suspended,
Archived,
}
impl Default for AccountStatus {
fn default() -> Self {
AccountStatus::Active
}
}
/// Represents the type of transaction
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TransactionType {
Transfer,
Clawback,
Freeze,
Unfreeze,
Issue,
Burn,
}
impl Default for TransactionType {
fn default() -> Self {
TransactionType::Transfer
}
}
/// Represents a signature for transactions
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Signature {
pub signer_id: u32,
pub signature: String,
pub timestamp: u64,
}
impl Signature {
pub fn new() -> Self {
Self {
signer_id: 0,
signature: String::new(),
timestamp: 0,
}
}
pub fn signer_id(mut self, signer_id: u32) -> Self {
self.signer_id = signer_id;
self
}
pub fn signature(mut self, signature: impl ToString) -> Self {
self.signature = signature.to_string();
self
}
pub fn timestamp(mut self, timestamp: u64) -> Self {
self.timestamp = timestamp;
self
}
pub fn build(self) -> Self {
self
}
}
/// Policy item for account operations
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct AccountPolicyItem {
pub signers: Vec<u32>,
pub min_signatures: u32,
pub enabled: bool,
pub threshold: f64,
pub recipient: u32,
}
impl AccountPolicyItem {
pub fn new() -> Self {
Self {
signers: Vec::new(),
min_signatures: 0,
enabled: false,
threshold: 0.0,
recipient: 0,
}
}
pub fn add_signer(mut self, signer_id: u32) -> Self {
self.signers.push(signer_id);
self
}
pub fn signers(mut self, signers: Vec<u32>) -> Self {
self.signers = signers;
self
}
pub fn min_signatures(mut self, min_signatures: u32) -> Self {
self.min_signatures = min_signatures;
self
}
pub fn enabled(mut self, enabled: bool) -> Self {
self.enabled = enabled;
self
}
pub fn threshold(mut self, threshold: f64) -> Self {
self.threshold = threshold;
self
}
pub fn recipient(mut self, recipient: u32) -> Self {
self.recipient = recipient;
self
}
pub fn build(self) -> Self {
self
}
}
/// Represents an account in the financial system
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Account {
/// Base model data
pub base_data: BaseModelData,
pub owner_id: u32,
#[index]
pub address: String,
pub balance: f64,
pub currency: String,
pub assetid: u32,
pub last_activity: u64,
pub administrators: Vec<u32>,
pub accountpolicy: u32,
}
impl Account {
/// Create a new account instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
owner_id: 0,
address: String::new(),
balance: 0.0,
currency: String::new(),
assetid: 0,
last_activity: 0,
administrators: Vec::new(),
accountpolicy: 0,
}
}
/// Set the owner ID (fluent)
pub fn owner_id(mut self, owner_id: u32) -> Self {
self.owner_id = owner_id;
self
}
/// Set the blockchain address (fluent)
pub fn address(mut self, address: impl ToString) -> Self {
self.address = address.to_string();
self
}
/// Set the balance (fluent)
pub fn balance(mut self, balance: f64) -> Self {
self.balance = balance;
self
}
/// Set the currency (fluent)
pub fn currency(mut self, currency: impl ToString) -> Self {
self.currency = currency.to_string();
self
}
/// Set the asset ID (fluent)
pub fn assetid(mut self, assetid: u32) -> Self {
self.assetid = assetid;
self
}
/// Set the last activity timestamp (fluent)
pub fn last_activity(mut self, last_activity: u64) -> Self {
self.last_activity = last_activity;
self
}
/// Add an administrator (fluent)
pub fn add_administrator(mut self, admin_id: u32) -> Self {
self.administrators.push(admin_id);
self
}
/// Set all administrators (fluent)
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
self.administrators = administrators;
self
}
/// Set the account policy ID (fluent)
pub fn accountpolicy(mut self, accountpolicy: u32) -> Self {
self.accountpolicy = accountpolicy;
self
}
/// Build the final account instance
pub fn build(self) -> Self {
self
}
}
/// Represents an asset in the financial system
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Asset {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub address: String,
pub assetid: u32,
pub asset_type: String,
pub issuer: u32,
pub supply: f64,
pub decimals: u8,
pub is_frozen: bool,
pub metadata: HashMap<String, String>,
pub administrators: Vec<u32>,
pub min_signatures: u32,
}
impl Asset {
/// Create a new asset instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
address: String::new(),
assetid: 0,
asset_type: String::new(),
issuer: 0,
supply: 0.0,
decimals: 0,
is_frozen: false,
metadata: HashMap::new(),
administrators: Vec::new(),
min_signatures: 0,
}
}
/// Set the blockchain address (fluent)
pub fn address(mut self, address: impl ToString) -> Self {
self.address = address.to_string();
self
}
/// Set the asset ID (fluent)
pub fn assetid(mut self, assetid: u32) -> Self {
self.assetid = assetid;
self
}
/// Set the asset type (fluent)
pub fn asset_type(mut self, asset_type: impl ToString) -> Self {
self.asset_type = asset_type.to_string();
self
}
/// Set the issuer (fluent)
pub fn issuer(mut self, issuer: u32) -> Self {
self.issuer = issuer;
self
}
/// Set the supply (fluent)
pub fn supply(mut self, supply: f64) -> Self {
self.supply = supply;
self
}
/// Set the decimals (fluent)
pub fn decimals(mut self, decimals: u8) -> Self {
self.decimals = decimals;
self
}
/// Set the frozen status (fluent)
pub fn is_frozen(mut self, is_frozen: bool) -> Self {
self.is_frozen = is_frozen;
self
}
/// Add metadata entry (fluent)
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
/// Set all metadata (fluent)
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
self.metadata = metadata;
self
}
/// Add an administrator (fluent)
pub fn add_administrator(mut self, admin_id: u32) -> Self {
self.administrators.push(admin_id);
self
}
/// Set all administrators (fluent)
pub fn administrators(mut self, administrators: Vec<u32>) -> Self {
self.administrators = administrators;
self
}
/// Set minimum signatures required (fluent)
pub fn min_signatures(mut self, min_signatures: u32) -> Self {
self.min_signatures = min_signatures;
self
}
/// Build the final asset instance
pub fn build(self) -> Self {
self
}
}
/// Represents account policies for various operations
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct AccountPolicy {
/// Base model data
pub base_data: BaseModelData,
pub transferpolicy: AccountPolicyItem,
pub adminpolicy: AccountPolicyItem,
pub clawbackpolicy: AccountPolicyItem,
pub freezepolicy: AccountPolicyItem,
}
impl AccountPolicy {
/// Create a new account policy instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
transferpolicy: AccountPolicyItem::new(),
adminpolicy: AccountPolicyItem::new(),
clawbackpolicy: AccountPolicyItem::new(),
freezepolicy: AccountPolicyItem::new(),
}
}
/// Set the transfer policy (fluent)
pub fn transferpolicy(mut self, transferpolicy: AccountPolicyItem) -> Self {
self.transferpolicy = transferpolicy;
self
}
/// Set the admin policy (fluent)
pub fn adminpolicy(mut self, adminpolicy: AccountPolicyItem) -> Self {
self.adminpolicy = adminpolicy;
self
}
/// Set the clawback policy (fluent)
pub fn clawbackpolicy(mut self, clawbackpolicy: AccountPolicyItem) -> Self {
self.clawbackpolicy = clawbackpolicy;
self
}
/// Set the freeze policy (fluent)
pub fn freezepolicy(mut self, freezepolicy: AccountPolicyItem) -> Self {
self.freezepolicy = freezepolicy;
self
}
/// Build the final account policy instance
pub fn build(self) -> Self {
self
}
}
/// Represents a financial transaction
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Transaction {
/// Base model data
pub base_data: BaseModelData,
pub txid: u32,
pub source: u32,
pub destination: u32,
pub assetid: u32,
pub amount: f64,
pub timestamp: u64,
pub status: String,
pub memo: String,
pub tx_type: TransactionType,
pub signatures: Vec<Signature>,
}
impl Transaction {
/// Create a new transaction instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
txid: 0,
source: 0,
destination: 0,
assetid: 0,
amount: 0.0,
timestamp: 0,
status: String::new(),
memo: String::new(),
tx_type: TransactionType::default(),
signatures: Vec::new(),
}
}
/// Set the transaction ID (fluent)
pub fn txid(mut self, txid: u32) -> Self {
self.txid = txid;
self
}
/// Set the source account (fluent)
pub fn source(mut self, source: u32) -> Self {
self.source = source;
self
}
/// Set the destination account (fluent)
pub fn destination(mut self, destination: u32) -> Self {
self.destination = destination;
self
}
/// Set the asset ID (fluent)
pub fn assetid(mut self, assetid: u32) -> Self {
self.assetid = assetid;
self
}
/// Set the amount (fluent)
pub fn amount(mut self, amount: f64) -> Self {
self.amount = amount;
self
}
/// Set the timestamp (fluent)
pub fn timestamp(mut self, timestamp: u64) -> Self {
self.timestamp = timestamp;
self
}
/// Set the status (fluent)
pub fn status(mut self, status: impl ToString) -> Self {
self.status = status.to_string();
self
}
/// Set the memo (fluent)
pub fn memo(mut self, memo: impl ToString) -> Self {
self.memo = memo.to_string();
self
}
/// Set the transaction type (fluent)
pub fn tx_type(mut self, tx_type: TransactionType) -> Self {
self.tx_type = tx_type;
self
}
/// Add a signature (fluent)
pub fn add_signature(mut self, signature: Signature) -> Self {
self.signatures.push(signature);
self
}
/// Set all signatures (fluent)
pub fn signatures(mut self, signatures: Vec<Signature>) -> Self {
self.signatures = signatures;
self
}
/// Build the final transaction instance
pub fn build(self) -> Self {
self
}
}

View File

@ -0,0 +1,142 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
/// Category of the secret box
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum SecretBoxCategory {
Profile,
}
impl Default for SecretBoxCategory {
fn default() -> Self {
SecretBoxCategory::Profile
}
}
/// Status of a notary
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum NotaryStatus {
Active,
Inactive,
Suspended,
Archived,
Error,
}
impl Default for NotaryStatus {
fn default() -> Self {
NotaryStatus::Active
}
}
/// Represents an encrypted secret box for storing sensitive data
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SecretBox {
pub notary_id: u32,
pub value: String,
pub version: u16,
pub timestamp: u64,
pub cat: SecretBoxCategory,
}
impl SecretBox {
pub fn new() -> Self {
Self {
notary_id: 0,
value: String::new(),
version: 1,
timestamp: 0,
cat: SecretBoxCategory::default(),
}
}
pub fn notary_id(mut self, notary_id: u32) -> Self {
self.notary_id = notary_id;
self
}
pub fn value(mut self, value: impl ToString) -> Self {
self.value = value.to_string();
self
}
pub fn version(mut self, version: u16) -> Self {
self.version = version;
self
}
pub fn timestamp(mut self, timestamp: u64) -> Self {
self.timestamp = timestamp;
self
}
pub fn cat(mut self, cat: SecretBoxCategory) -> Self {
self.cat = cat;
self
}
pub fn build(self) -> Self {
self
}
}
/// Represents a notary who can decrypt secret boxes
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Notary {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub userid: u32,
pub status: NotaryStatus,
pub myceliumaddress: String,
#[index]
pub pubkey: String,
}
impl Notary {
/// Create a new notary instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
userid: 0,
status: NotaryStatus::default(),
myceliumaddress: String::new(),
pubkey: String::new(),
}
}
/// Set the user ID (fluent)
pub fn userid(mut self, userid: u32) -> Self {
self.userid = userid;
self
}
/// Set the notary status (fluent)
pub fn status(mut self, status: NotaryStatus) -> Self {
self.status = status;
self
}
/// Set the mycelium address (fluent)
pub fn myceliumaddress(mut self, myceliumaddress: impl ToString) -> Self {
self.myceliumaddress = myceliumaddress.to_string();
self
}
/// Set the public key (fluent)
pub fn pubkey(mut self, pubkey: impl ToString) -> Self {
self.pubkey = pubkey.to_string();
self
}
/// Build the final notary instance
pub fn build(self) -> Self {
self
}
}

View File

@ -0,0 +1,120 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
/// Status of a signature
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum SignatureStatus {
Active,
Inactive,
Pending,
Revoked,
}
impl Default for SignatureStatus {
fn default() -> Self {
SignatureStatus::Pending
}
}
/// Type of object being signed
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ObjectType {
Account,
DNSRecord,
Membership,
User,
Transaction,
KYC,
}
impl Default for ObjectType {
fn default() -> Self {
ObjectType::User
}
}
/// Represents a cryptographic signature for various objects
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct Signature {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub signature_id: u32,
#[index]
pub user_id: u32,
pub value: String,
#[index]
pub objectid: u32,
pub objecttype: ObjectType,
pub status: SignatureStatus,
pub timestamp: u64,
}
impl Signature {
/// Create a new signature instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
signature_id: 0,
user_id: 0,
value: String::new(),
objectid: 0,
objecttype: ObjectType::default(),
status: SignatureStatus::default(),
timestamp: 0,
}
}
/// Set the signature ID (fluent)
pub fn signature_id(mut self, signature_id: u32) -> Self {
self.signature_id = signature_id;
self
}
/// Set the user ID (fluent)
pub fn user_id(mut self, user_id: u32) -> Self {
self.user_id = user_id;
self
}
/// Set the signature value (fluent)
pub fn value(mut self, value: impl ToString) -> Self {
self.value = value.to_string();
self
}
/// Set the object ID (fluent)
pub fn objectid(mut self, objectid: u32) -> Self {
self.objectid = objectid;
self
}
/// Set the object type (fluent)
pub fn objecttype(mut self, objecttype: ObjectType) -> Self {
self.objecttype = objecttype;
self
}
/// Set the signature status (fluent)
pub fn status(mut self, status: SignatureStatus) -> Self {
self.status = status;
self
}
/// Set the timestamp (fluent)
pub fn timestamp(mut self, timestamp: u64) -> Self {
self.timestamp = timestamp;
self
}
/// Build the final signature instance
pub fn build(self) -> Self {
self
}
}

View File

@ -0,0 +1,370 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// Represents the status of a user in the system
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum UserStatus {
Active,
Inactive,
Suspended,
Archived,
}
impl Default for UserStatus {
fn default() -> Self {
UserStatus::Active
}
}
/// Represents the KYC status of a user
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum KYCStatus {
Pending,
Approved,
Rejected,
}
impl Default for KYCStatus {
fn default() -> Self {
KYCStatus::Pending
}
}
/// User profile information
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct UserProfile {
pub user_id: u32,
pub full_name: String,
pub bio: String,
pub profile_pic: String,
pub links: HashMap<String, String>,
pub metadata: HashMap<String, String>,
}
impl UserProfile {
pub fn new() -> Self {
Self {
user_id: 0,
full_name: String::new(),
bio: String::new(),
profile_pic: String::new(),
links: HashMap::new(),
metadata: HashMap::new(),
}
}
pub fn user_id(mut self, user_id: u32) -> Self {
self.user_id = user_id;
self
}
pub fn full_name(mut self, full_name: impl ToString) -> Self {
self.full_name = full_name.to_string();
self
}
pub fn bio(mut self, bio: impl ToString) -> Self {
self.bio = bio.to_string();
self
}
pub fn profile_pic(mut self, profile_pic: impl ToString) -> Self {
self.profile_pic = profile_pic.to_string();
self
}
pub fn add_link(mut self, key: impl ToString, value: impl ToString) -> Self {
self.links.insert(key.to_string(), value.to_string());
self
}
pub fn links(mut self, links: HashMap<String, String>) -> Self {
self.links = links;
self
}
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
self.metadata = metadata;
self
}
pub fn build(self) -> Self {
self
}
}
/// KYC (Know Your Customer) information for a user
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct KYCInfo {
pub user_id: u32,
pub full_name: String,
pub date_of_birth: u64,
pub address: String,
pub phone_number: String,
pub id_number: String,
pub id_type: String,
pub id_expiry: u64,
pub kyc_status: KYCStatus,
pub kyc_verified: bool,
pub kyc_verified_by: u32,
pub kyc_verified_at: u64,
pub kyc_rejected_reason: String,
pub kyc_signature: u32,
pub metadata: HashMap<String, String>,
}
impl KYCInfo {
pub fn new() -> Self {
Self {
user_id: 0,
full_name: String::new(),
date_of_birth: 0,
address: String::new(),
phone_number: String::new(),
id_number: String::new(),
id_type: String::new(),
id_expiry: 0,
kyc_status: KYCStatus::default(),
kyc_verified: false,
kyc_verified_by: 0,
kyc_verified_at: 0,
kyc_rejected_reason: String::new(),
kyc_signature: 0,
metadata: HashMap::new(),
}
}
pub fn user_id(mut self, user_id: u32) -> Self {
self.user_id = user_id;
self
}
pub fn full_name(mut self, full_name: impl ToString) -> Self {
self.full_name = full_name.to_string();
self
}
pub fn date_of_birth(mut self, date_of_birth: u64) -> Self {
self.date_of_birth = date_of_birth;
self
}
pub fn address(mut self, address: impl ToString) -> Self {
self.address = address.to_string();
self
}
pub fn phone_number(mut self, phone_number: impl ToString) -> Self {
self.phone_number = phone_number.to_string();
self
}
pub fn id_number(mut self, id_number: impl ToString) -> Self {
self.id_number = id_number.to_string();
self
}
pub fn id_type(mut self, id_type: impl ToString) -> Self {
self.id_type = id_type.to_string();
self
}
pub fn id_expiry(mut self, id_expiry: u64) -> Self {
self.id_expiry = id_expiry;
self
}
pub fn kyc_status(mut self, kyc_status: KYCStatus) -> Self {
self.kyc_status = kyc_status;
self
}
pub fn kyc_verified(mut self, kyc_verified: bool) -> Self {
self.kyc_verified = kyc_verified;
self
}
pub fn kyc_verified_by(mut self, kyc_verified_by: u32) -> Self {
self.kyc_verified_by = kyc_verified_by;
self
}
pub fn kyc_verified_at(mut self, kyc_verified_at: u64) -> Self {
self.kyc_verified_at = kyc_verified_at;
self
}
pub fn kyc_rejected_reason(mut self, kyc_rejected_reason: impl ToString) -> Self {
self.kyc_rejected_reason = kyc_rejected_reason.to_string();
self
}
pub fn kyc_signature(mut self, kyc_signature: u32) -> Self {
self.kyc_signature = kyc_signature;
self
}
pub fn add_metadata(mut self, key: impl ToString, value: impl ToString) -> Self {
self.metadata.insert(key.to_string(), value.to_string());
self
}
pub fn metadata(mut self, metadata: HashMap<String, String>) -> Self {
self.metadata = metadata;
self
}
pub fn build(self) -> Self {
self
}
}
/// Represents a secret box for storing encrypted data
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct SecretBox {
pub data: Vec<u8>,
pub nonce: Vec<u8>,
}
impl SecretBox {
pub fn new() -> Self {
Self {
data: Vec::new(),
nonce: Vec::new(),
}
}
pub fn data(mut self, data: Vec<u8>) -> Self {
self.data = data;
self
}
pub fn nonce(mut self, nonce: Vec<u8>) -> Self {
self.nonce = nonce;
self
}
pub fn build(self) -> Self {
self
}
}
/// Represents a user in the heroledger system
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct User {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub username: String,
#[index]
pub pubkey: String,
pub email: Vec<String>,
pub status: UserStatus,
pub userprofile: Vec<SecretBox>,
pub kyc: Vec<SecretBox>,
}
impl Default for User {
fn default() -> Self {
Self {
base_data: BaseModelData::new(),
username: String::new(),
pubkey: String::new(),
email: Vec::new(),
status: UserStatus::default(),
userprofile: Vec::new(),
kyc: Vec::new(),
}
}
}
impl User {
/// Create a new user instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
username: String::new(),
pubkey: String::new(),
email: Vec::new(),
status: UserStatus::default(),
userprofile: Vec::new(),
kyc: Vec::new(),
}
}
/// Get the user ID
pub fn id(&self) -> u32 {
self.base_data.id
}
/// Set the username (fluent)
pub fn username(mut self, username: impl ToString) -> Self {
self.username = username.to_string();
self
}
/// Set the public key (fluent)
pub fn pubkey(mut self, pubkey: impl ToString) -> Self {
self.pubkey = pubkey.to_string();
self
}
/// Add an email address (fluent)
pub fn add_email(mut self, email: impl ToString) -> Self {
self.email.push(email.to_string());
self
}
/// Set all email addresses (fluent)
pub fn email(mut self, email: Vec<String>) -> Self {
self.email = email;
self
}
/// Set the user status (fluent)
pub fn status(mut self, status: UserStatus) -> Self {
self.status = status;
self
}
/// Add a user profile secret box (fluent)
pub fn add_userprofile(mut self, profile: SecretBox) -> Self {
self.userprofile.push(profile);
self
}
/// Set all user profile secret boxes (fluent)
pub fn userprofile(mut self, userprofile: Vec<SecretBox>) -> Self {
self.userprofile = userprofile;
self
}
/// Add a KYC secret box (fluent)
pub fn add_kyc(mut self, kyc: SecretBox) -> Self {
self.kyc.push(kyc);
self
}
/// Set all KYC secret boxes (fluent)
pub fn kyc(mut self, kyc: Vec<SecretBox>) -> Self {
self.kyc = kyc;
self
}
/// Build the final user instance
pub fn build(self) -> Self {
self
}
}

View File

@ -0,0 +1,120 @@
use heromodels_core::{Model, BaseModelData, IndexKey};
use heromodels_derive::model;
use serde::{Deserialize, Serialize};
use super::secretbox::SecretBox;
/// Represents a per-user key-value store
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct UserKVS {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub userid: u32,
pub name: String,
}
impl UserKVS {
/// Create a new user KVS instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
userid: 0,
name: String::new(),
}
}
/// Set the user ID (fluent)
pub fn userid(mut self, userid: u32) -> Self {
self.userid = userid;
self
}
/// Set the KVS name (fluent)
pub fn name(mut self, name: impl ToString) -> Self {
self.name = name.to_string();
self
}
/// Build the final user KVS instance
pub fn build(self) -> Self {
self
}
}
/// Represents an item in a user's key-value store
#[model]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct UserKVSItem {
/// Base model data
pub base_data: BaseModelData,
#[index]
pub userkvs_id: u32,
pub key: String,
pub value: String,
pub secretbox: Vec<SecretBox>,
pub timestamp: u64,
}
impl UserKVSItem {
/// Create a new user KVS item instance
pub fn new(id: u32) -> Self {
let mut base_data = BaseModelData::new();
base_data.update_id(id);
Self {
base_data,
userkvs_id: 0,
key: String::new(),
value: String::new(),
secretbox: Vec::new(),
timestamp: 0,
}
}
/// Set the user KVS ID (fluent)
pub fn userkvs_id(mut self, userkvs_id: u32) -> Self {
self.userkvs_id = userkvs_id;
self
}
/// Set the key (fluent)
pub fn key(mut self, key: impl ToString) -> Self {
self.key = key.to_string();
self
}
/// Set the value (fluent)
pub fn value(mut self, value: impl ToString) -> Self {
self.value = value.to_string();
self
}
/// Add a secret box (fluent)
pub fn add_secretbox(mut self, secretbox: SecretBox) -> Self {
self.secretbox.push(secretbox);
self
}
/// Set all secret boxes (fluent)
pub fn secretbox(mut self, secretbox: Vec<SecretBox>) -> Self {
self.secretbox = secretbox;
self
}
/// Set the timestamp (fluent)
pub fn timestamp(mut self, timestamp: u64) -> Self {
self.timestamp = timestamp;
self
}
/// Build the final user KVS item instance
pub fn build(self) -> Self {
self
}
}

View File

@ -10,6 +10,7 @@ pub mod contact;
pub mod finance;
pub mod flow;
pub mod governance;
pub mod heroledger;
pub mod legal;
pub mod library;
pub mod object;