# Modular Architecture Templates for Streamlit Container Runtime

## Overview
Professional modular architecture templates based on validated Container Runtime patterns. These templates enable clean, scalable, and maintainable Streamlit applications.

## Architecture Principles

### 1. Separation of Concerns
- **Database Layer**: Data access and Snowpark integration
- **API Layer**: External service integration and data fetching
- **Business Logic**: Data processing and application logic
- **UI Layer**: User interface components and interactions
- **Utility Layer**: Shared utilities and helper functions

### 2. Module Organization
- Each module has single responsibility
- Clean interfaces between modules
- Minimal dependencies and coupling
- Easy to test and maintain
- Professional code structure

### 3. Container Runtime Optimizations
- All modules designed for single-stage deployment
- Efficient caching patterns
- Performance-optimized database queries
- Proper error handling throughout

## Core Architecture Template

### Main Application Structure
```
project_name/
├── main_app.py          # Application entry point
├── database_module.py   # Database and Snowpark integration
├── api_module.py        # External API integration
├── processing_module.py # Business logic and data processing
├── ui_components.py     # Reusable UI components
├── utils.py            # Shared utilities
└── config.py           # Configuration management
```

## Template Files

### 1. Main Application (main_app.py)
```python
"""
Main Application Entry Point
Professional Streamlit Container Runtime Application
"""

import streamlit as st
import database_module
import api_module
import processing_module
import ui_components
import utils
import config

# Page configuration
st.set_page_config(
    page_title=config.APP_TITLE,
    page_icon=config.APP_ICON,
    layout="wide",
    initial_sidebar_state="expanded"
)

def initialize_application():
    """Initialize application components"""
    try:
        # Initialize database connection
        if not database_module.initialize_connection():
            st.error("❌ Database initialization failed")
            st.stop()
        
        # Initialize external APIs (if needed)
        api_module.initialize_clients()
        
        # Set up application state
        utils.initialize_session_state()
        
        return True
        
    except Exception as e:
        st.error(f"❌ Application initialization failed: {str(e)}")
        st.stop()
        return False

def main():
    """Main application logic"""
    
    # Initialize application
    initialize_application()
    
    # Render header
    ui_components.render_header()
    
    # Render sidebar navigation
    page = ui_components.render_sidebar()
    
    # Render main content based on navigation
    if page == "Dashboard":
        render_dashboard()
    elif page == "Data Analysis":
        render_data_analysis()
    elif page == "Settings":
        render_settings()
    else:
        render_dashboard()  # Default page

def render_dashboard():
    """Render dashboard page"""
    st.header("📊 Dashboard")
    
    # Get dashboard data
    with st.spinner("Loading dashboard data..."):
        data = database_module.get_dashboard_data()
    
    if not data.empty:
        # Render metrics
        ui_components.render_metrics(data)
        
        # Render charts
        ui_components.render_charts(data)
    else:
        st.warning("No data available for dashboard")

def render_data_analysis():
    """Render data analysis page"""
    st.header("🔍 Data Analysis")
    
    # Analysis interface
    ui_components.render_analysis_interface()

def render_settings():
    """Render settings page"""
    st.header("⚙️ Settings")
    
    # Settings interface
    ui_components.render_settings_interface()

if __name__ == "__main__":
    main()
```

### 2. Database Module (database_module.py)
```python
"""
Database Module - Snowpark Integration
Handles all database operations with Container Runtime optimizations
"""

import streamlit as st
from snowflake.snowpark.context import get_active_session
import pandas as pd
from typing import Optional, Dict, Any
import config

# Session management
@st.cache_resource
def get_snowpark_session():
    """Get cached Snowpark session for Container Runtime"""
    return get_active_session()

def initialize_connection() -> bool:
    """Initialize and validate database connection"""
    try:
        session = get_snowpark_session()
        
        # Test connection
        result = session.sql("SELECT CURRENT_USER(), CURRENT_DATABASE(), CURRENT_SCHEMA()").collect()
        user, db, schema = result[0]
        
        st.success(f"✅ Connected as {user} to {db}.{schema}")
        return True
        
    except Exception as e:
        st.error(f"❌ Database connection failed: {str(e)}")
        return False

@st.cache_data(ttl=config.CACHE_TTL)
def get_dashboard_data() -> pd.DataFrame:
    """Get dashboard data with caching"""
    try:
        session = get_snowpark_session()
        
        query = """
        SELECT 
            date_column,
            metric_1,
            metric_2,
            category
        FROM {table_name}
        WHERE date_column >= CURRENT_DATE - 30
        ORDER BY date_column DESC
        LIMIT 1000
        """.format(table_name=config.MAIN_TABLE)
        
        return session.sql(query).to_pandas()
        
    except Exception as e:
        st.error(f"Database query failed: {str(e)}")
        return pd.DataFrame()

@st.cache_data(ttl=config.CACHE_TTL)
def get_filtered_data(filters: Dict[str, Any]) -> pd.DataFrame:
    """Get filtered data based on user selections"""
    try:
        session = get_snowpark_session()
        
        # Build dynamic query based on filters
        where_conditions = []
        for key, value in filters.items():
            if value:
                where_conditions.append(f"{key} = '{value}'")
        
        where_clause = "WHERE " + " AND ".join(where_conditions) if where_conditions else ""
        
        query = f"""
        SELECT * FROM {config.MAIN_TABLE}
        {where_clause}
        ORDER BY date_column DESC
        LIMIT {config.MAX_ROWS}
        """
        
        return session.sql(query).to_pandas()
        
    except Exception as e:
        st.error(f"Filtered query failed: {str(e)}")
        return pd.DataFrame()

def execute_custom_query(query: str) -> Optional[pd.DataFrame]:
    """Execute custom query with error handling"""
    try:
        session = get_snowpark_session()
        return session.sql(query).to_pandas()
        
    except Exception as e:
        st.error(f"Query execution failed: {str(e)}")
        return None

def get_table_info(table_name: str) -> Dict[str, Any]:
    """Get table structure and metadata"""
    try:
        session = get_snowpark_session()
        
        # Get column information
        columns_query = f"DESCRIBE TABLE {table_name}"
        columns_df = session.sql(columns_query).to_pandas()
        
        # Get row count
        count_query = f"SELECT COUNT(*) as row_count FROM {table_name}"
        count_result = session.sql(count_query).collect()
        row_count = count_result[0][0]
        
        return {
            "columns": columns_df,
            "row_count": row_count,
            "table_name": table_name
        }
        
    except Exception as e:
        st.error(f"Failed to get table info: {str(e)}")
        return {}
```

### 3. API Module (api_module.py)
```python
"""
API Module - External Service Integration
Handles external API calls with proper error handling
"""

import streamlit as st
import requests
import pandas as pd
from typing import Dict, Any, Optional, List
import config
import utils

class APIClient:
    """Base API client with common functionality"""
    
    def __init__(self, base_url: str, api_key: Optional[str] = None):
        self.base_url = base_url
        self.api_key = api_key
        self.session = requests.Session()
        
        if api_key:
            self.session.headers.update({"Authorization": f"Bearer {api_key}"})

    def make_request(self, endpoint: str, method: str = "GET", **kwargs) -> Optional[Dict]:
        """Make HTTP request with error handling"""
        try:
            url = f"{self.base_url}/{endpoint.lstrip('/')}"
            
            response = self.session.request(method, url, **kwargs)
            response.raise_for_status()
            
            return response.json()
            
        except requests.exceptions.RequestException as e:
            st.error(f"API request failed: {str(e)}")
            return None
        except Exception as e:
            st.error(f"Unexpected API error: {str(e)}")
            return None

# Global API clients
_api_clients = {}

def initialize_clients():
    """Initialize API clients"""
    global _api_clients
    
    try:
        # Initialize your API clients here
        if config.EXTERNAL_API_URL:
            _api_clients['main_api'] = APIClient(
                base_url=config.EXTERNAL_API_URL,
                api_key=config.EXTERNAL_API_KEY
            )
        
        st.success("✅ API clients initialized")
        
    except Exception as e:
        st.error(f"❌ API initialization failed: {str(e)}")

def get_api_client(client_name: str = 'main_api') -> Optional[APIClient]:
    """Get API client by name"""
    return _api_clients.get(client_name)

@st.cache_data(ttl=config.API_CACHE_TTL)
def fetch_external_data(endpoint: str, params: Dict[str, Any] = None) -> Optional[pd.DataFrame]:
    """Fetch data from external API with caching"""
    client = get_api_client()
    if not client:
        st.error("API client not initialized")
        return None
    
    try:
        response = client.make_request(endpoint, params=params)
        if response and 'data' in response:
            return pd.DataFrame(response['data'])
        else:
            st.warning("No data returned from API")
            return pd.DataFrame()
            
    except Exception as e:
        st.error(f"Failed to fetch external data: {str(e)}")
        return None

@st.cache_data(ttl=config.API_CACHE_TTL)
def search_external_service(query: str, filters: Dict[str, Any] = None) -> List[Dict]:
    """Search external service with caching"""
    client = get_api_client()
    if not client:
        return []
    
    try:
        params = {"q": query}
        if filters:
            params.update(filters)
        
        response = client.make_request("search", params=params)
        return response.get('results', []) if response else []
        
    except Exception as e:
        st.error(f"Search failed: {str(e)}")
        return []

def post_data_to_external_service(data: Dict[str, Any]) -> bool:
    """Post data to external service"""
    client = get_api_client()
    if not client:
        return False
    
    try:
        response = client.make_request("data", method="POST", json=data)
        return response is not None
        
    except Exception as e:
        st.error(f"Failed to post data: {str(e)}")
        return False
```

### 4. Processing Module (processing_module.py)
```python
"""
Processing Module - Business Logic
Handles data processing and business logic operations
"""

import streamlit as st
import pandas as pd
import numpy as np
from typing import Dict, Any, List, Optional
import config
import utils

def process_dashboard_data(raw_data: pd.DataFrame) -> Dict[str, Any]:
    """Process raw data for dashboard display"""
    try:
        if raw_data.empty:
            return {"metrics": {}, "charts": {}, "tables": {}}
        
        # Calculate key metrics
        metrics = calculate_key_metrics(raw_data)
        
        # Prepare chart data
        charts = prepare_chart_data(raw_data)
        
        # Prepare table data
        tables = prepare_table_data(raw_data)
        
        return {
            "metrics": metrics,
            "charts": charts,
            "tables": tables,
            "last_updated": utils.get_current_timestamp()
        }
        
    except Exception as e:
        st.error(f"Data processing failed: {str(e)}")
        return {"metrics": {}, "charts": {}, "tables": {}}

def calculate_key_metrics(data: pd.DataFrame) -> Dict[str, Any]:
    """Calculate key performance metrics"""
    try:
        metrics = {}
        
        if 'metric_1' in data.columns:
            metrics['total_metric_1'] = data['metric_1'].sum()
            metrics['avg_metric_1'] = data['metric_1'].mean()
        
        if 'metric_2' in data.columns:
            metrics['total_metric_2'] = data['metric_2'].sum()
            metrics['avg_metric_2'] = data['metric_2'].mean()
        
        if 'date_column' in data.columns:
            metrics['date_range'] = {
                'start': data['date_column'].min(),
                'end': data['date_column'].max()
            }
        
        metrics['total_records'] = len(data)
        
        return metrics
        
    except Exception as e:
        st.error(f"Metrics calculation failed: {str(e)}")
        return {}

def prepare_chart_data(data: pd.DataFrame) -> Dict[str, pd.DataFrame]:
    """Prepare data for various chart types"""
    try:
        charts = {}
        
        # Time series chart
        if 'date_column' in data.columns and 'metric_1' in data.columns:
            time_series = data.groupby('date_column')['metric_1'].sum().reset_index()
            charts['time_series'] = time_series
        
        # Category breakdown
        if 'category' in data.columns and 'metric_2' in data.columns:
            category_breakdown = data.groupby('category')['metric_2'].sum().reset_index()
            charts['category_breakdown'] = category_breakdown
        
        # Distribution chart
        if 'metric_1' in data.columns:
            charts['distribution'] = data[['metric_1']]
        
        return charts
        
    except Exception as e:
        st.error(f"Chart data preparation failed: {str(e)}")
        return {}

def prepare_table_data(data: pd.DataFrame) -> Dict[str, pd.DataFrame]:
    """Prepare data for table displays"""
    try:
        tables = {}
        
        # Summary table
        if 'category' in data.columns:
            summary = data.groupby('category').agg({
                'metric_1': ['sum', 'mean', 'count'],
                'metric_2': ['sum', 'mean']
            }).round(2)
            
            # Flatten column names
            summary.columns = ['_'.join(col).strip() for col in summary.columns.values]
            summary = summary.reset_index()
            
            tables['summary'] = summary
        
        # Recent records table
        if 'date_column' in data.columns:
            recent = data.nlargest(10, 'date_column')
            tables['recent'] = recent
        
        # Top performers table
        if 'metric_1' in data.columns:
            top_performers = data.nlargest(10, 'metric_1')
            tables['top_performers'] = top_performers
        
        return tables
        
    except Exception as e:
        st.error(f"Table data preparation failed: {str(e)}")
        return {}

def apply_filters(data: pd.DataFrame, filters: Dict[str, Any]) -> pd.DataFrame:
    """Apply user-selected filters to data"""
    try:
        filtered_data = data.copy()
        
        for column, value in filters.items():
            if value and column in filtered_data.columns:
                if isinstance(value, list):
                    filtered_data = filtered_data[filtered_data[column].isin(value)]
                else:
                    filtered_data = filtered_data[filtered_data[column] == value]
        
        return filtered_data
        
    except Exception as e:
        st.error(f"Filter application failed: {str(e)}")
        return data

def generate_insights(data: pd.DataFrame) -> List[str]:
    """Generate automatic insights from data"""
    try:
        insights = []
        
        if not data.empty:
            # Basic insights
            insights.append(f"Dataset contains {len(data):,} records")
            
            if 'date_column' in data.columns:
                date_range = data['date_column'].max() - data['date_column'].min()
                insights.append(f"Data spans {date_range.days} days")
            
            if 'category' in data.columns:
                top_category = data['category'].value_counts().index[0]
                insights.append(f"Most common category: {top_category}")
            
            if 'metric_1' in data.columns:
                trend = "increasing" if data['metric_1'].is_monotonic_increasing else "varying"
                insights.append(f"Metric 1 trend is {trend}")
        
        return insights
        
    except Exception as e:
        st.error(f"Insight generation failed: {str(e)}")
        return ["Unable to generate insights"]
```

### 5. UI Components Module (ui_components.py)
```python
"""
UI Components Module - Reusable Interface Elements
Professional UI components for Container Runtime applications
"""

import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from typing import Dict, Any, List, Optional
import config

def render_header():
    """Render application header"""
    st.title(config.APP_TITLE)
    st.markdown(config.APP_DESCRIPTION)
    
    # Add header metrics or status
    col1, col2, col3 = st.columns(3)
    with col1:
        st.metric("Status", "🟢 Active")
    with col2:
        st.metric("Last Updated", "Just now")
    with col3:
        st.metric("Version", config.APP_VERSION)

def render_sidebar() -> str:
    """Render sidebar navigation and return selected page"""
    st.sidebar.title("Navigation")
    
    pages = ["Dashboard", "Data Analysis", "Settings"]
    
    selected_page = st.sidebar.radio(
        "Select Page",
        pages,
        key="navigation"
    )
    
    # Add sidebar filters or controls
    st.sidebar.markdown("---")
    st.sidebar.subheader("Quick Actions")
    
    if st.sidebar.button("Refresh Data"):
        st.cache_data.clear()
        st.success("Data refreshed!")
    
    return selected_page

def render_metrics(data: pd.DataFrame):
    """Render metrics display"""
    if data.empty:
        st.warning("No data available for metrics")
        return
    
    st.subheader("📊 Key Metrics")
    
    # Calculate metrics
    total_records = len(data)
    
    if 'metric_1' in data.columns:
        total_metric_1 = data['metric_1'].sum()
        avg_metric_1 = data['metric_1'].mean()
    else:
        total_metric_1, avg_metric_1 = 0, 0
    
    if 'metric_2' in data.columns:
        total_metric_2 = data['metric_2'].sum()
    else:
        total_metric_2 = 0
    
    # Display metrics in columns
    col1, col2, col3, col4 = st.columns(4)
    
    with col1:
        st.metric("Total Records", f"{total_records:,}")
    
    with col2:
        st.metric("Total Metric 1", f"{total_metric_1:,.0f}")
    
    with col3:
        st.metric("Avg Metric 1", f"{avg_metric_1:.1f}")
    
    with col4:
        st.metric("Total Metric 2", f"{total_metric_2:,.0f}")

def render_charts(data: pd.DataFrame):
    """Render chart visualizations"""
    if data.empty:
        st.warning("No data available for charts")
        return
    
    st.subheader("📈 Data Visualizations")
    
    # Time series chart
    if 'date_column' in data.columns and 'metric_1' in data.columns:
        fig_time = px.line(
            data, 
            x='date_column', 
            y='metric_1',
            title="Metric 1 Over Time"
        )
        st.plotly_chart(fig_time, use_container_width=True)
    
    # Category breakdown
    if 'category' in data.columns and 'metric_2' in data.columns:
        category_data = data.groupby('category')['metric_2'].sum().reset_index()
        
        fig_category = px.bar(
            category_data,
            x='category',
            y='metric_2',
            title="Metric 2 by Category"
        )
        st.plotly_chart(fig_category, use_container_width=True)

def render_data_table(data: pd.DataFrame, title: str = "Data Table"):
    """Render interactive data table"""
    st.subheader(title)
    
    if data.empty:
        st.info("No data to display")
        return
    
    # Add filters
    if len(data) > 100:
        col1, col2 = st.columns(2)
        with col1:
            show_all = st.checkbox("Show all rows", value=False)
        with col2:
            if not show_all:
                n_rows = st.slider("Number of rows", 10, min(len(data), 1000), 100)
                data = data.head(n_rows)
    
    # Display table
    st.dataframe(data, use_container_width=True)
    
    # Download button
    csv = data.to_csv(index=False)
    st.download_button(
        label="Download CSV",
        data=csv,
        file_name=f"{title.lower().replace(' ', '_')}.csv",
        mime="text/csv"
    )

def render_filter_panel(data: pd.DataFrame) -> Dict[str, Any]:
    """Render filter panel and return selected filters"""
    st.subheader("🔍 Filters")
    
    filters = {}
    
    if 'category' in data.columns:
        categories = ['All'] + list(data['category'].unique())
        selected_category = st.selectbox("Category", categories)
        if selected_category != 'All':
            filters['category'] = selected_category
    
    if 'date_column' in data.columns:
        date_range = st.date_input(
            "Date Range",
            value=(data['date_column'].min(), data['date_column'].max()),
            min_value=data['date_column'].min(),
            max_value=data['date_column'].max()
        )
        if len(date_range) == 2:
            filters['date_range'] = date_range
    
    return filters

def render_analysis_interface():
    """Render data analysis interface"""
    st.markdown("### Custom Query Interface")
    
    query = st.text_area(
        "Enter SQL Query:",
        placeholder="SELECT * FROM table_name LIMIT 100",
        height=100
    )
    
    if st.button("Execute Query"):
        if query.strip():
            import database_module
            result = database_module.execute_custom_query(query)
            if result is not None:
                render_data_table(result, "Query Results")
        else:
            st.warning("Please enter a query")

def render_settings_interface():
    """Render settings interface"""
    st.markdown("### Application Settings")
    
    # Cache management
    st.markdown("#### Cache Management")
    col1, col2 = st.columns(2)
    
    with col1:
        if st.button("Clear Data Cache"):
            st.cache_data.clear()
            st.success("Data cache cleared!")
    
    with col2:
        if st.button("Clear Resource Cache"):
            st.cache_resource.clear()
            st.success("Resource cache cleared!")
    
    # Configuration display
    st.markdown("#### Current Configuration")
    st.json({
        "App Title": config.APP_TITLE,
        "Version": config.APP_VERSION,
        "Cache TTL": f"{config.CACHE_TTL} seconds",
        "Max Rows": config.MAX_ROWS
    })

def show_loading_spinner(message: str = "Loading..."):
    """Show loading spinner with message"""
    return st.spinner(message)

def display_error_message(error: str, details: Optional[str] = None):
    """Display formatted error message"""
    st.error(f"❌ {error}")
    if details:
        with st.expander("Error Details"):
            st.code(details)

def display_success_message(message: str):
    """Display formatted success message"""
    st.success(f"✅ {message}")

def display_warning_message(message: str):
    """Display formatted warning message"""
    st.warning(f"⚠️ {message}")

def display_info_message(message: str):
    """Display formatted info message"""
    st.info(f"ℹ️ {message}")
```

### 6. Configuration Module (config.py)
```python
"""
Configuration Module
Centralized application configuration
"""

# Application Information
APP_TITLE = "Professional Streamlit Application"
APP_DESCRIPTION = "Built with Container Runtime best practices"
APP_VERSION = "1.0.0"
APP_ICON = "📊"

# Database Configuration
MAIN_TABLE = "your_main_table"
MAX_ROWS = 10000

# Caching Configuration
CACHE_TTL = 300  # 5 minutes
API_CACHE_TTL = 600  # 10 minutes

# External API Configuration
EXTERNAL_API_URL = ""  # Set your API URL
EXTERNAL_API_KEY = ""  # Set your API key

# UI Configuration
DEFAULT_PAGE_SIZE = 100
CHART_HEIGHT = 400

# Performance Settings
MAX_CONCURRENT_QUERIES = 5
QUERY_TIMEOUT = 30  # seconds
```

### 7. Utilities Module (utils.py)
```python
"""
Utilities Module
Shared utility functions and helpers
"""

import streamlit as st
import pandas as pd
from datetime import datetime, timezone
from typing import Any, Dict, Optional

def initialize_session_state():
    """Initialize Streamlit session state variables"""
    if 'initialized' not in st.session_state:
        st.session_state.initialized = True
        st.session_state.filters = {}
        st.session_state.last_refresh = datetime.now()

def get_current_timestamp() -> str:
    """Get current timestamp as string"""
    return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")

def format_number(value: float, decimals: int = 2) -> str:
    """Format number for display"""
    if value >= 1_000_000:
        return f"{value / 1_000_000:.1f}M"
    elif value >= 1_000:
        return f"{value / 1_000:.1f}K"
    else:
        return f"{value:.{decimals}f}"

def safe_divide(numerator: float, denominator: float) -> float:
    """Safely divide two numbers"""
    try:
        return numerator / denominator if denominator != 0 else 0.0
    except (TypeError, ZeroDivisionError):
        return 0.0

def validate_dataframe(df: pd.DataFrame, required_columns: list) -> bool:
    """Validate DataFrame has required columns"""
    missing_columns = [col for col in required_columns if col not in df.columns]
    if missing_columns:
        st.error(f"Missing required columns: {missing_columns}")
        return False
    return True

def clean_dataframe(df: pd.DataFrame) -> pd.DataFrame:
    """Clean DataFrame for display"""
    # Remove null values
    df_clean = df.dropna()
    
    # Format numeric columns
    numeric_columns = df_clean.select_dtypes(include=['float64', 'int64']).columns
    for col in numeric_columns:
        if df_clean[col].dtype == 'float64':
            df_clean[col] = df_clean[col].round(2)
    
    return df_clean

def export_to_csv(data: pd.DataFrame, filename: str) -> str:
    """Export DataFrame to CSV string"""
    return data.to_csv(index=False)

def log_action(action: str, details: Dict[str, Any] = None):
    """Log user action (for debugging)"""
    timestamp = get_current_timestamp()
    log_entry = {
        "timestamp": timestamp,
        "action": action,
        "details": details or {}
    }
    
    # In development, you might want to log to console
    # In production, consider using proper logging
    if st.secrets.get("DEBUG_MODE", False):
        st.write("Debug Log:", log_entry)

def handle_error(error: Exception, context: str = ""):
    """Handle errors with consistent formatting"""
    error_message = f"Error in {context}: {str(error)}" if context else str(error)
    st.error(f"❌ {error_message}")
    
    # In development, show full traceback
    if st.secrets.get("DEBUG_MODE", False):
        st.exception(error)

def get_filter_state(key: str, default: Any = None) -> Any:
    """Get filter state from session"""
    return st.session_state.filters.get(key, default)

def set_filter_state(key: str, value: Any):
    """Set filter state in session"""
    st.session_state.filters[key] = value

def reset_filters():
    """Reset all filters"""
    st.session_state.filters = {}
    st.success("Filters reset")
```

## Usage Instructions

### 1. Deployment Steps
1. Upload all module files to Snowflake stage with `AUTO_COMPRESS=FALSE`
2. Create Streamlit application using `FROM '@stage/'` syntax
3. Specify compute pool and external access integration
4. Launch and test application

### 2. Customization
- Update `config.py` with your specific settings
- Modify database queries in `database_module.py`
- Add your API integrations in `api_module.py`
- Customize UI components in `ui_components.py`
- Add business logic in `processing_module.py`

### 3. Testing
- Test each module independently
- Validate all imports work correctly
- Check performance with realistic data volumes
- Test error handling scenarios

This modular architecture template provides a professional foundation for scalable Streamlit Container Runtime applications with clean separation of concerns and optimized performance patterns.