Backend Shared Crate in Rust
Find a file
Benjamin Slingo 2a72d6e17e Update reqwest to fix rustls-pemfile security issue
Also update .gitignore to exclude XCFramework build artifacts.
2025-12-19 21:20:08 -05:00
RTSDA Initial commit: Church Core Rust library 2025-08-16 19:25:01 -04:00
src Update reqwest to fix rustls-pemfile security issue 2025-12-19 21:20:08 -05:00
tests/video_processing Remove obsolete test files referencing deprecated API 2025-12-02 09:49:52 -05:00
.gitignore Update reqwest to fix rustls-pemfile security issue 2025-12-19 21:20:08 -05:00
build.rs Add hymnal support with responsive readings and URL security hardening 2025-12-02 09:47:06 -05:00
build_ios.sh Add hymnal support with responsive readings and URL security hardening 2025-12-02 09:47:06 -05:00
build_ios_hymnarium.sh Update reqwest to fix rustls-pemfile security issue 2025-12-19 21:20:08 -05:00
Cargo.toml Update reqwest to fix rustls-pemfile security issue 2025-12-19 21:20:08 -05:00
church_core_architecture.md Refactor church-core for modularity, maintainability, and cross-platform support 2025-10-24 00:48:24 -04:00
HYMNAL_FRONTEND_INTEGRATION.md Add hymnal support with responsive readings and URL security hardening 2025-12-02 09:47:06 -05:00
Makefile Initial commit: Church Core Rust library 2025-08-16 19:25:01 -04:00
MIGRATION.md Migrate video_processing and bulletin modules into church-core with security hardening 2025-11-03 17:40:53 -05:00
README.md Refactor church-core for modularity, maintainability, and cross-platform support 2025-10-24 00:48:24 -04:00

Church Core

A shared Rust crate providing unified API access and data models for church applications across multiple platforms (iOS, Android, Web, Desktop).

Overview

Church Core centralizes all church application logic, API communication, and data management into a single, well-tested Rust crate. This enables client applications to become "dumb display devices" while ensuring consistency across platforms.

Features

  • Unified API Client: Single interface for all church APIs
  • Consistent Data Models: Shared types for events, bulletins, sermons, etc.
  • Cross-Platform Support: Native bindings for iOS, Android, WASM, and FFI
  • Built-in Caching: Automatic response caching with TTL
  • Offline Support: Graceful offline operation with cached data
  • Authentication: PocketBase and Jellyfin integration
  • Error Handling: Comprehensive error types with retry logic
  • Type Safety: Rust's type system prevents API mismatches

Architecture

church-core/
├── src/
│   ├── types/           # Pure data models (platform-agnostic)
│   │   ├── event.rs     # Event models
│   │   ├── bulletin.rs  # Bulletin models
│   │   ├── sermon.rs    # Sermon models
│   │   ├── contact.rs   # Contact models
│   │   ├── auth.rs      # Authentication models
│   │   ├── bible.rs     # Bible verse models
│   │   ├── config.rs    # Configuration models
│   │   ├── streaming.rs # Livestream models
│   │   └── ...          # Other type definitions
│   │
│   ├── api/             # API client (trait-based, platform abstraction)
│   │   ├── mod.rs       # ApiClient trait definition
│   │   ├── native.rs    # Native/iOS implementation (reqwest)
│   │   ├── wasm.rs      # WASM implementation (future)
│   │   └── endpoints.rs # URL builders
│   │
│   ├── validation/      # Business logic validation
│   │   ├── common.rs    # Email, phone validation
│   │   ├── contact.rs   # Contact form validation
│   │   └── event.rs     # Event validation
│   │
│   ├── client/          # Legacy HTTP client (being deprecated)
│   │   ├── events.rs    # Event operations
│   │   ├── bulletins.rs # Bulletin operations
│   │   ├── sermons.rs   # Sermon operations
│   │   └── ...
│   │
│   ├── uniffi/          # iOS UniFFI bindings
│   │   ├── events.rs    # Event functions
│   │   ├── bible.rs     # Bible functions
│   │   ├── config.rs    # Config functions
│   │   └── ...          # Other iOS bindings
│   │
│   ├── auth/            # Authentication modules
│   ├── cache/           # Caching system
│   ├── utils/           # Utility functions
│   ├── config.rs        # Configuration
│   ├── error.rs         # Error types
│   └── lib.rs           # Main entry point
│
├── church_core.udl      # UniFFI interface definition
├── build.rs             # Build script (UniFFI scaffolding)
└── README.md

Quick Start

Basic Usage

use church_core::{ChurchApiClient, ChurchCoreConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create client with default configuration
    let config = ChurchCoreConfig::default();
    let client = ChurchApiClient::new(config)?;
    
    // Get upcoming events
    let events = client.get_upcoming_events(Some(10)).await?;
    for event in events {
        println!("{}: {}", event.title, event.start_time);
    }
    
    // Get current bulletin
    if let Some(bulletin) = client.get_current_bulletin().await? {
        println!("Current bulletin: {}", bulletin.title);
    }
    
    // Submit contact form
    let contact = ContactForm::new(
        "John Doe".to_string(),
        "john@example.com".to_string(),
        "Prayer Request".to_string(),
        "Please pray for my family.".to_string()
    );
    let submission_id = client.submit_contact_form(contact).await?;
    println!("Contact form submitted: {}", submission_id);
    
    Ok(())
}

Custom Configuration

use church_core::{ChurchApiClient, ChurchCoreConfig};
use std::time::Duration;

let config = ChurchCoreConfig::new()
    .with_base_url("https://api.mychurch.org/api")
    .with_cache_ttl(Duration::from_secs(600))
    .with_timeout(Duration::from_secs(15))
    .with_retry_attempts(5)
    .with_offline_mode(true);

let client = ChurchApiClient::new(config)?;

Data Models

Event

use church_core::{Event, EventCategory, NewEvent};
use chrono::{DateTime, Utc};

// Create a new event
let new_event = NewEvent {
    title: "Bible Study".to_string(),
    description: "Weekly Bible study group".to_string(),
    start_time: Utc::now(),
    end_time: Utc::now() + chrono::Duration::hours(2),
    location: "Fellowship Hall".to_string(),
    location_url: Some("https://maps.google.com/...".to_string()),
    category: EventCategory::Education,
    is_featured: true,
    // ... other fields
};

let event_id = client.create_event(new_event).await?;

Bulletin

use church_core::{Bulletin, NewBulletin};
use chrono::NaiveDate;

// Get current bulletin
if let Some(bulletin) = client.get_current_bulletin().await? {
    println!("Sabbath School: {}", bulletin.sabbath_school);
    println!("Divine Worship: {}", bulletin.divine_worship);
    
    // Check for announcements
    for announcement in bulletin.active_announcements() {
        println!("📢 {}: {}", announcement.title, announcement.content);
    }
}

Contact Form

use church_core::{ContactForm, ContactCategory, VisitorInfo};

let contact = ContactForm::new(
    "Jane Smith".to_string(),
    "jane@example.com".to_string(),
    "New Visitor".to_string(),
    "I'm interested in learning more about your church.".to_string()
)
.with_category(ContactCategory::Visitor)
.with_phone("555-123-4567".to_string())
.with_visitor_info(VisitorInfo {
    is_first_time: true,
    wants_follow_up: true,
    wants_newsletter: true,
    // ... other fields
});

let submission_id = client.submit_contact_form(contact).await?;

Authentication

PocketBase Authentication

use church_core::auth::{LoginRequest, AuthToken};

// Authenticate with PocketBase
let login = LoginRequest {
    identity: "admin@church.org".to_string(),
    password: "secure_password".to_string(),
};

// Note: Authentication methods would be implemented in auth module
// let token = client.authenticate_pocketbase(login).await?;
// client.set_auth_token(token).await;

Caching

The client automatically caches responses with configurable TTL:

// Cache is automatically used
let events = client.get_upcoming_events(None).await?; // Fetches from API
let events = client.get_upcoming_events(None).await?; // Returns from cache

// Manual cache management
client.clear_cache().await;
let (cache_size, max_size) = client.get_cache_stats().await;

Error Handling

use church_core::{ChurchApiError, Result};

match client.get_event("invalid-id").await {
    Ok(Some(event)) => println!("Found event: {}", event.title),
    Ok(None) => println!("Event not found"),
    Err(ChurchApiError::NotFound) => println!("Event does not exist"),
    Err(ChurchApiError::Network(_)) => println!("Network error - check connection"),
    Err(ChurchApiError::Auth(_)) => println!("Authentication required"),
    Err(e) => println!("Other error: {}", e),
}

Platform Integration

iOS (Swift via UniFFI)

import church_core

// Fetch events (returns JSON string)
let eventsJSON = fetch_events_json()

// Fetch bulletins
let bulletinsJSON = fetch_bulletins_json()

// Submit contact form
let result = submit_contact_v2_json(
    name: "John Doe",
    email: "john@example.com",
    subject: "Question",
    message: "Hello!",
    phone: "555-1234"
)

// Validate email
if validate_email_address(email: "test@example.com") {
    print("Valid email")
}

// Get church config
let churchName = get_church_name()
let coordinates = get_coordinates()

Native Rust

use church_core::{ChurchApiClient, ChurchCoreConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = ChurchCoreConfig::default();
    let client = ChurchApiClient::new(config)?;

    let events = client.get_upcoming_events(Some(10)).await?;
    println!("Found {} events", events.len());

    Ok(())
}

Web (WASM) - Coming Soon

WASM support is planned with the trait-based api::ApiClient architecture already in place.

Testing

Run the test binary to verify API connectivity:

cargo run --bin church-core-test

This will test:

  • Health check endpoint
  • Upcoming events retrieval
  • Current bulletin fetching
  • Configuration loading
  • Cache statistics

API Endpoints

The client interfaces with these standard endpoints:

  • GET /events/upcoming - Get upcoming events
  • GET /events/{id} - Get single event
  • POST /events - Create event
  • GET /bulletins/current - Get current bulletin
  • GET /bulletins - List bulletins
  • GET /config - Get church configuration
  • POST /contact - Submit contact form
  • GET /sermons - List sermons
  • GET /sermons/search - Search sermons

Recent Improvements (v0.2.0)

Codebase Restructuring

The codebase has been significantly restructured for better maintainability:

  • Renamed models/types/ - More accurate naming for pure data types
  • New api/ module - Trait-based architecture ready for WASM
  • New validation/ module - Centralized business logic validation
  • Cleaned up UniFFI - Removed 1,767 lines of redundant wrapper code
  • Better feature flags - Clear separation: native, wasm, ios
  • Optional dependencies - Only include what you need for each platform

Code Reduction

  • ~20% smaller codebase - Removed redundant wrappers and duplicated code
  • Modular organization - Clear separation of concerns
  • DRY/KISS principles - No duplication, simple design patterns

Architecture Benefits

  • Cross-platform ready - Trait-based design supports multiple targets
  • Zero breaking changes - All iOS functions preserved
  • Easy to extend - Clear module boundaries for new features
  • Better testing - Validation logic separated from API code

Development

Building for iOS (No Python Required!)

# Quick build using Makefile
make ios

# Or use the build script directly
./build_ios.sh

# Install dependencies first time
make install-deps

# Development build (faster)
make dev

# Clean build artifacts
make clean

Building Steps Explained

  1. Install iOS targets: Adds Rust toolchains for iOS devices and simulators
  2. Build static libraries: Creates .a files for each iOS architecture
  3. Create universal library: Combines all architectures using lipo
  4. Generate Swift bindings: Uses uniffi-bindgen to create Swift interfaces
  5. Copy to iOS project: Moves all files to your Xcode project

Generated files:

  • church_core.swift - Swift interface to your Rust code
  • church_coreFFI.h - C header file
  • church_coreFFI.modulemap - Module map for Swift
  • libchurch_core.a - Universal static library

Standard Rust Building

# Standard build
cargo build

# Build with WASM support
cargo build --features wasm

# Build with UniFFI support
cargo build --features uniffi

# Run tests
cargo test --features uniffi

Features

  • default: Native Rust client (includes native)
  • native: Native platform features (tokio, moka cache)
  • wasm: WebAssembly bindings (future)
  • ios: iOS bindings via UniFFI
  • server: Server-side usage (alias for native)

License

MIT License - see LICENSE file for details.

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

Support

For issues and questions:

  • Check the API documentation
  • Review existing GitHub issues
  • Create a new issue with detailed information