# 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/ │ ├── client/ # HTTP client and API modules │ │ ├── events.rs # Event operations │ │ ├── bulletins.rs # Bulletin operations │ │ ├── sermons.rs # Sermon operations │ │ ├── contact.rs # Contact form handling │ │ └── config.rs # Configuration management │ ├── models/ # Data structures │ │ ├── event.rs # Event models │ │ ├── bulletin.rs # Bulletin models │ │ ├── sermon.rs # Sermon models │ │ ├── contact.rs # Contact models │ │ └── auth.rs # Authentication models │ ├── auth/ # Authentication modules │ ├── cache/ # Caching system │ ├── utils/ # Utility functions │ └── error.rs # Error types └── README.md ``` ## Quick Start ### Basic Usage ```rust use church_core::{ChurchApiClient, ChurchCoreConfig}; #[tokio::main] async fn main() -> Result<(), Box> { // 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 ```rust 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 ```rust 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 ```rust 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 ```rust 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 ```rust 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: ```rust // 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 ```rust 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) ```swift // FFI bindings would be generated for iOS import ChurchCore let client = ChurchApiClient() client.getUpcomingEvents(limit: 10) { events in // Handle events } ``` ### Android (Kotlin/Java) ```kotlin // JNI bindings for Android import org.church.ChurchCore val client = ChurchCore() val events = client.getUpcomingEvents(10) ``` ### Web (WASM) ```javascript // WASM bindings for web import { ChurchApiClient } from 'church-core-wasm'; const client = new ChurchApiClient(); const events = await client.getUpcomingEvents(10); ``` ## Testing Run the test binary to verify API connectivity: ```bash 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 ## Development ### Building for iOS (No Python Required!) ```bash # 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 ```bash # 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 - `wasm`: WebAssembly bindings - `uniffi`: UniFFI bindings for iOS/Android (replaces old `ffi` feature) - `native`: Native platform features ## 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