# Event Filtering System - Usage and Integration Guide ## Overview This document provides practical examples and integration patterns for using the event filtering system in the smokesignal-eTD application. It demonstrates how to implement filtering with both dynamic user inputs and fixed query templates for specific use cases. ## Table of Contents 1. [Basic Usage Patterns](#basic-usage-patterns) 2. [Fixed Query Templates](#fixed-query-templates) 3. [Integration Examples](#integration-examples) 4. [API Reference](#api-reference) 5. [Template Usage](#template-usage) 6. [Performance Optimization](#performance-optimization) 7. [Error Handling](#error-handling) ## Basic Usage Patterns ### 1. Simple Text Search ```rust use crate::filtering::{EventFilterCriteria, FilteringService}; // Basic text search for "conference" events let criteria = EventFilterCriteria { search_text: Some("conference".to_string()), ..Default::default() }; let service = FilteringService::new(pool.clone()); let results = service.filter_events(&criteria, 1, 20).await?; ``` ### 2. Date Range Filtering ```rust use chrono::{DateTime, Utc}; let criteria = EventFilterCriteria { date_from: Some(DateTime::parse_from_rfc3339("2025-06-01T00:00:00Z")?.with_timezone(&Utc)), date_to: Some(DateTime::parse_from_rfc3339("2025-12-31T23:59:59Z")?.with_timezone(&Utc)), ..Default::default() }; let results = service.filter_events(&criteria, 1, 50).await?; ``` ### 3. Location-Based Filtering ```rust let criteria = EventFilterCriteria { location_text: Some("Montreal".to_string()), location_radius_km: Some(25.0), ..Default::default() }; let results = service.filter_events(&criteria, 1, 30).await?; ``` ## Fixed Query Templates ### Template 1: Upcoming Tech Events Perfect for embedding in tech-focused pages or newsletters. ```rust use crate::filtering::{EventFilterCriteria, FilteringService}; use chrono::{DateTime, Utc, Duration}; pub struct TechEventsTemplate; impl TechEventsTemplate { /// Get upcoming tech events in the next 30 days pub async fn get_upcoming_tech_events( service: &FilteringService, location: Option, ) -> Result { let now = Utc::now(); let thirty_days = now + Duration::days(30); let criteria = EventFilterCriteria { // Tech-related keywords search_text: Some("technology OR programming OR developer OR startup OR AI OR software OR web OR mobile OR data".to_string()), // Only future events date_from: Some(now), date_to: Some(thirty_days), // Optional location filter location_text: location, location_radius_km: Some(50.0), // Sort by date ascending (soonest first) sort_by: Some("date_asc".to_string()), ..Default::default() }; // Get first 10 results service.filter_events(&criteria, 1, 10).await } } // Usage example let tech_events = TechEventsTemplate::get_upcoming_tech_events( &service, Some("San Francisco".to_string()) ).await?; ``` ### Template 2: Weekend Community Events Ideal for community pages or local event discovery. ```rust pub struct CommunityEventsTemplate; impl CommunityEventsTemplate { /// Get community events happening this weekend pub async fn get_weekend_community_events( service: &FilteringService, city: &str, ) -> Result { let now = Utc::now(); let days_until_saturday = (6 - now.weekday().num_days_from_monday()) % 7; let saturday = now + Duration::days(days_until_saturday as i64); let sunday = saturday + Duration::days(1); let criteria = EventFilterCriteria { // Community-focused keywords search_text: Some("community OR meetup OR networking OR social OR volunteer OR local OR neighborhood".to_string()), // Weekend timeframe date_from: Some(saturday), date_to: Some(sunday + Duration::hours(23) + Duration::minutes(59)), // Specific city location_text: Some(city.to_string()), location_radius_km: Some(25.0), // Sort by popularity (most RSVPs first) sort_by: Some("popularity_desc".to_string()), ..Default::default() }; service.filter_events(&criteria, 1, 15).await } } // Usage example let weekend_events = CommunityEventsTemplate::get_weekend_community_events( &service, "Toronto" ).await?; ``` ### Template 3: Free Educational Events Great for student portals or educational institutions. ```rust pub struct EducationalEventsTemplate; impl EducationalEventsTemplate { /// Get free educational events in the next 60 days pub async fn get_free_educational_events( service: &FilteringService, subject_area: Option, ) -> Result { let now = Utc::now(); let sixty_days = now + Duration::days(60); let mut search_terms = vec![ "workshop", "seminar", "lecture", "course", "tutorial", "training", "learning", "education", "free", "no cost" ]; // Add subject-specific terms if provided if let Some(subject) = &subject_area { search_terms.push(subject); } let criteria = EventFilterCriteria { search_text: Some(search_terms.join(" OR ")), // Next 60 days date_from: Some(now), date_to: Some(sixty_days), // Filter for likely free events // This could be enhanced with a dedicated "free" field // Sort by date ascending sort_by: Some("date_asc".to_string()), ..Default::default() }; service.filter_events(&criteria, 1, 20).await } } // Usage examples let programming_workshops = EducationalEventsTemplate::get_free_educational_events( &service, Some("programming".to_string()) ).await?; let general_education = EducationalEventsTemplate::get_free_educational_events( &service, None ).await?; ``` ### Template 4: Tonight's Events Perfect for "what's happening tonight" widgets. ```rust pub struct TonightEventsTemplate; impl TonightEventsTemplate { /// Get events happening tonight in a specific area pub async fn get_tonights_events( service: &FilteringService, location: &str, radius_km: f64, ) -> Result { let now = Utc::now(); let tonight_start = now.date_naive().and_hms_opt(18, 0, 0) .unwrap().and_local_timezone(Utc).unwrap(); let tonight_end = now.date_naive().and_hms_opt(23, 59, 59) .unwrap().and_local_timezone(Utc).unwrap(); let criteria = EventFilterCriteria { // Evening/night events date_from: Some(tonight_start), date_to: Some(tonight_end), // Location constraint location_text: Some(location.to_string()), location_radius_km: Some(radius_km), // Sort by start time sort_by: Some("date_asc".to_string()), ..Default::default() }; service.filter_events(&criteria, 1, 10).await } } // Usage example let tonight = TonightEventsTemplate::get_tonights_events( &service, "Vancouver", 15.0 ).await?; ``` ## Integration Examples ### 1. Axum Route Handler with Fixed Template ```rust use axum::{extract::State, response::Html, Extension}; use crate::http::context::WebContext; use crate::filtering::FilteringService; pub async fn handle_tech_events_page( State(context): State, Extension(user_location): Extension>, ) -> Result, AppError> { let service = FilteringService::new(context.storage_pool.clone()); // Use the fixed template let events = TechEventsTemplate::get_upcoming_tech_events( &service, user_location ).await?; // Render template let rendered = context.handlebars.render("tech_events_page", &json!({ "events": events.events, "facets": events.facets, "total_count": events.total_count, "page_title": "Upcoming Tech Events" }))?; Ok(Html(rendered)) } ``` ### 2. HTMX Widget for Dashboard ```rust pub async fn handle_weekend_events_widget( State(context): State, Query(params): Query>, ) -> Result, AppError> { let city = params.get("city").cloned() .unwrap_or_else(|| "Montreal".to_string()); let service = FilteringService::new(context.storage_pool.clone()); let events = CommunityEventsTemplate::get_weekend_community_events( &service, &city ).await?; // Render as HTMX partial let rendered = context.handlebars.render("weekend_events_widget", &json!({ "events": events.events, "city": city }))?; Ok(Html(rendered)) } ``` ### 3. API Endpoint for Mobile App ```rust use axum::Json; use serde_json::json; pub async fn api_tonight_events( State(context): State, Query(params): Query>, ) -> Result, AppError> { let location = params.get("location") .ok_or_else(|| AppError::BadRequest("location parameter required".to_string()))?; let radius = params.get("radius") .and_then(|r| r.parse::().ok()) .unwrap_or(10.0); let service = FilteringService::new(context.storage_pool.clone()); let events = TonightEventsTemplate::get_tonights_events( &service, location, radius ).await?; Ok(Json(json!({ "success": true, "data": { "events": events.events, "total_count": events.total_count, "location": location, "radius_km": radius } }))) } ``` ## API Reference ### FilteringService Methods ```rust impl FilteringService { /// Create a new filtering service instance pub fn new(pool: sqlx::PgPool) -> Self; /// Filter events with full criteria support pub async fn filter_events( &self, criteria: &EventFilterCriteria, page: i64, page_size: i64, ) -> Result; /// Get facet counts for refining filters pub async fn calculate_facets( &self, criteria: &EventFilterCriteria, ) -> Result; /// Hydrate events with additional data pub async fn hydrate_events( &self, events: &mut [Event], strategy: HydrationStrategy, ) -> Result<(), FilteringError>; } ``` ### EventFilterCriteria Fields ```rust pub struct EventFilterCriteria { /// Text search across event content pub search_text: Option, /// Filter by date range pub date_from: Option>, pub date_to: Option>, /// Location-based filtering pub location_text: Option, pub location_latitude: Option, pub location_longitude: Option, pub location_radius_km: Option, /// Event type filtering pub event_types: Option>, /// Organizer filtering pub organizer_handles: Option>, /// Sorting options pub sort_by: Option, // "date_asc", "date_desc", "popularity_desc", "relevance" /// Language filtering pub languages: Option>, } ``` ## Template Usage ### 1. Tech Events Page Template ```handlebars {{!-- templates/tech_events_page.en-us.html --}}

{{tr "tech-events-title"}}

{{tr "tech-events-subtitle"}}

{{#each events}}

{{title}}

{{format_date start_time}}

{{location.name}}

{{truncate description 150}}

{{/each}}
{{#if (gt total_count events.length)}}

{{tr "view-all-tech-events"}}

{{/if}}
``` ### 2. Weekend Events Widget ```handlebars {{!-- templates/weekend_events_widget.en-us.incl.html --}}

{{tr "this-weekend-in"}} {{city}}

{{#if events}} {{else}}

{{tr "no-weekend-events"}}

{{/if}}
``` ### 3. Tonight's Events Notification ```handlebars {{!-- templates/tonight_events_notification.en-us.incl.html --}} {{#if events}}
{{tr "happening-tonight"}}: {{#each events}} {{title}}{{#unless @last}}, {{/unless}} {{/each}}
{{/if}} ``` ## Performance Optimization ### 1. Caching Fixed Templates ```rust use redis::AsyncCommands; impl TechEventsTemplate { pub async fn get_cached_tech_events( service: &FilteringService, redis: &mut redis::aio::Connection, location: Option, ) -> Result { let cache_key = format!("tech_events:{}", location.as_deref().unwrap_or("global")); // Try cache first if let Ok(cached) = redis.get::<_, String>(&cache_key).await { if let Ok(events) = serde_json::from_str(&cached) { return Ok(events); } } // Fallback to database let events = Self::get_upcoming_tech_events(service, location).await?; // Cache for 15 minutes let serialized = serde_json::to_string(&events)?; let _: () = redis.setex(&cache_key, 900, serialized).await?; Ok(events) } } ``` ### 2. Background Updates ```rust use tokio::time::{interval, Duration}; pub async fn start_template_cache_updater( service: FilteringService, redis_pool: redis::aio::ConnectionManager, ) { let mut interval = interval(Duration::from_secs(600)); // 10 minutes loop { interval.tick().await; // Update popular templates let cities = vec!["Montreal", "Toronto", "Vancouver", "Calgary"]; for city in cities { if let Ok(mut conn) = redis_pool.clone().into_connection().await { let _ = TechEventsTemplate::get_cached_tech_events( &service, &mut conn, Some(city.to_string()) ).await; let _ = CommunityEventsTemplate::get_weekend_community_events( &service, city ).await; } } } } ``` ## Error Handling ### 1. Graceful Degradation ```rust pub async fn handle_tech_events_safe( service: &FilteringService, location: Option, ) -> FilteredEventsResult { match TechEventsTemplate::get_upcoming_tech_events(service, location).await { Ok(events) => events, Err(err) => { tracing::error!("Failed to fetch tech events: {}", err); // Return empty result with error indication FilteredEventsResult { events: vec![], facets: EventFacets::default(), total_count: 0, has_more: false, error_message: Some("Unable to load events at this time".to_string()), } } } } ``` ### 2. Fallback Templates ```rust impl TechEventsTemplate { pub async fn get_tech_events_with_fallback( service: &FilteringService, location: Option, ) -> Result { // Try specific tech events first if let Ok(events) = Self::get_upcoming_tech_events(service, location.clone()).await { if !events.events.is_empty() { return Ok(events); } } // Fallback to broader search let criteria = EventFilterCriteria { search_text: Some("event OR meetup OR conference".to_string()), date_from: Some(Utc::now()), date_to: Some(Utc::now() + Duration::days(30)), location_text: location, location_radius_km: Some(50.0), sort_by: Some("date_asc".to_string()), ..Default::default() }; service.filter_events(&criteria, 1, 10).await } } ``` ## Integration Checklist ### Before Using Fixed Templates - [ ] Database migrations applied (`20250530104334_event_filtering_indexes.sql`) - [ ] Environment variable `DATABASE_URL` configured - [ ] Redis connection available (for caching) - [ ] Handlebars templates created for your use case - [ ] Localization strings added to `i18n/*/ui.ftl` files - [ ] Error handling implemented for your specific needs ### Template Implementation Steps 1. **Define your fixed criteria** in a template struct 2. **Implement the query method** using `EventFilterCriteria` 3. **Create the route handler** in your Axum router 4. **Add the Handlebars template** for rendering 5. **Add localization strings** for user-facing text 6. **Implement caching** for frequently-used templates 7. **Add error handling** and fallback behavior 8. **Test with realistic data** to verify performance ### Performance Considerations - **Cache frequently-used templates** (tech events, weekend events) - **Use background jobs** to pre-populate cache - **Implement fallback queries** for when specific searches return no results - **Monitor query performance** and adjust indexes as needed - **Consider pagination** for templates that might return many results --- This guide provides a complete reference for integrating the event filtering system with fixed query templates. The examples demonstrate real-world usage patterns that can be adapted for specific application needs while maintaining performance and user experience. *Generated: May 30, 2025 Author: GitHub Copilot Version: Usage Guide v1.0*