4_✅_Compliance.py
1 """ 2 333 Method Analytics Dashboard - Compliance Page 3 """ 4 5 import logging 6 import streamlit as st 7 from streamlit_autorefresh import st_autorefresh 8 from dashboard import config 9 from dashboard.utils import database 10 from dashboard.components import metrics 11 from dashboard.utils.logging_config import configure_app_logging, log_exception 12 13 # Configure logging for this page 14 logger = configure_app_logging("dashboard.compliance") 15 16 # Page configuration 17 st.set_page_config(page_title="Compliance", page_icon="✅", layout="wide") 18 19 # Auto-refresh 20 st_autorefresh(interval=config.REFRESH_INTERVAL * 1000, key="compliance_refresh") 21 22 st.title("⚖️ Compliance & Rate Limits") 23 24 # === Key Metrics === 25 try: 26 optout_stats = database.get_optout_stats() 27 platform_health = database.get_platform_health() 28 29 email_optouts = ( 30 optout_stats["total_email_optouts"].iloc[0] if not optout_stats.empty else 0 31 ) 32 sms_optouts = ( 33 optout_stats["total_sms_optouts"].iloc[0] if not optout_stats.empty else 0 34 ) 35 36 metrics.display_metric_grid( 37 [ 38 {"label": "Email Opt-outs", "value": f"{email_optouts:,}"}, 39 {"label": "SMS Opt-outs", "value": f"{sms_optouts:,}"}, 40 { 41 "label": "Total Opt-outs", 42 "value": f"{email_optouts + sms_optouts:,}", 43 }, 44 ] 45 ) 46 47 st.markdown("---") 48 49 # === Platform Health & Rate Limits === 50 st.subheader("📊 Platform Health & Rate Limits") 51 52 # Resend (Email) Health 53 st.write("**📧 Resend.com Health**") 54 55 if not platform_health.empty: 56 email_data = platform_health[platform_health["contact_method"] == "email"] 57 58 if not email_data.empty: 59 bounce_rate = email_data["bounce_rate"].iloc[0] 60 delivery_rate = email_data["delivery_rate"].iloc[0] 61 total_sent = email_data["total_sent"].iloc[0] 62 bounced = email_data["bounced"].iloc[0] 63 64 # Alert logic 65 if bounce_rate > config.RESEND_BOUNCE_CRITICAL: 66 st.error( 67 f"🚨 CRITICAL: Bounce rate is {bounce_rate}% (>{config.RESEND_BOUNCE_CRITICAL}%)" 68 ) 69 st.warning( 70 "**Recommendation:** Immediate list cleaning required. High bounce rates damage sender reputation." 71 ) 72 elif bounce_rate > config.RESEND_BOUNCE_ALERT: 73 st.warning( 74 f"⚠️ ALERT: Bounce rate is {bounce_rate}% (>{config.RESEND_BOUNCE_ALERT}%)" 75 ) 76 st.info( 77 "**Recommendation:** Consider list cleaning and removing invalid addresses." 78 ) 79 else: 80 st.success(f"✅ Bounce rate is healthy: {bounce_rate}%") 81 82 # Email metrics 83 email_cols = st.columns(4) 84 with email_cols[0]: 85 st.metric("Total Sent", f"{total_sent:,}") 86 with email_cols[1]: 87 st.metric("Delivery Rate", f"{delivery_rate}%") 88 with email_cols[2]: 89 st.metric("Bounce Rate", f"{bounce_rate}%") 90 with email_cols[3]: 91 st.metric("Bounced", f"{bounced:,}") 92 93 # Note: Complaint rate would come from email tracking 94 st.info("💡 Complaint rate tracking: Coming soon via Resend webhooks") 95 else: 96 st.info("No email outreach data available") 97 else: 98 st.info("No platform health data available") 99 100 st.markdown("---") 101 102 # Twilio (SMS) Health 103 st.write("**📱 Twilio Health**") 104 105 if not platform_health.empty: 106 sms_data = platform_health[platform_health["contact_method"] == "sms"] 107 108 if not sms_data.empty: 109 sms_delivery_rate = sms_data["delivery_rate"].iloc[0] 110 sms_bounce_rate = sms_data["bounce_rate"].iloc[0] 111 sms_total_sent = sms_data["total_sent"].iloc[0] 112 113 if sms_delivery_rate < 95: 114 st.warning(f"⚠️ SMS delivery rate is {sms_delivery_rate}% (<95%)") 115 st.info( 116 "**Recommendation:** Review message templates for carrier filtering issues." 117 ) 118 else: 119 st.success(f"✅ SMS delivery rate is healthy: {sms_delivery_rate}%") 120 121 sms_cols = st.columns(3) 122 with sms_cols[0]: 123 st.metric("Total Sent", f"{sms_total_sent:,}") 124 with sms_cols[1]: 125 st.metric("Delivery Rate", f"{sms_delivery_rate}%") 126 with sms_cols[2]: 127 st.metric("Failed Rate", f"{sms_bounce_rate}%") 128 else: 129 st.info("No SMS outreach data available") 130 else: 131 st.info("No SMS data available") 132 133 st.markdown("---") 134 135 # Other Platform Limits 136 st.subheader("🔧 Other Platform Limits") 137 138 limits_cols = st.columns(3) 139 140 with limits_cols[0]: 141 st.write("**ZenRows API**") 142 st.info("Daily API calls: Coming soon") 143 st.caption("Plan limit tracking TBD") 144 145 with limits_cols[1]: 146 st.write("**OpenRouter**") 147 st.info("Token usage: Coming soon") 148 st.caption("Budget tracking TBD") 149 150 with limits_cols[2]: 151 st.write("**Playwright**") 152 st.info("Concurrent instances: Coming soon") 153 st.caption("Resource monitoring TBD") 154 155 st.markdown("---") 156 157 # === Compliance Checklist === 158 st.subheader("✅ Compliance Checklist") 159 160 checklist_cols = st.columns(2) 161 162 with checklist_cols[0]: 163 st.write("**CAN-SPAM (Email)**") 164 st.checkbox("✅ Unsubscribe link in all emails", value=True, disabled=True) 165 st.checkbox("✅ Sender identification present", value=True, disabled=True) 166 st.checkbox("✅ Physical address included", value=True, disabled=True) 167 st.checkbox("✅ Honor opt-outs within 10 days", value=True, disabled=True) 168 169 with checklist_cols[1]: 170 st.write("**TCPA (SMS)**") 171 st.checkbox("✅ Opt-out instructions (STOP)", value=True, disabled=True) 172 st.checkbox("✅ Business hours only (8am-9pm)", value=True, disabled=True) 173 st.checkbox("✅ Sender identification", value=True, disabled=True) 174 st.checkbox("✅ E.164 phone format", value=True, disabled=True) 175 176 st.markdown("---") 177 178 # === Platform Health Table === 179 st.subheader("Platform Summary") 180 if not platform_health.empty: 181 st.dataframe( 182 platform_health[ 183 [ 184 "contact_method", 185 "total_sent", 186 "delivered", 187 "delivery_rate", 188 "bounced", 189 "bounce_rate", 190 ] 191 ], 192 use_container_width=True, 193 hide_index=True, 194 column_config={ 195 "delivery_rate": st.column_config.NumberColumn( 196 "Delivery %", format="%.2f%%" 197 ), 198 "bounce_rate": st.column_config.NumberColumn( 199 "Bounce %", format="%.2f%%" 200 ), 201 }, 202 ) 203 else: 204 st.info("No platform data available") 205 206 except Exception as e: 207 log_exception(logger, f"Error loading compliance data: {e}") 208 st.error(f"Error loading compliance data: {e}")