"""Projects overview page - Hub for all portfolio projects.""" from typing import Any import dash import dash_mantine_components as dmc from dash import dcc from dash_iconify import DashIconify dash.register_page(__name__, path="/projects", name="Projects") # Page intro INTRO_TEXT = ( "These are projects I've built—some professional (anonymized where needed), " "some personal. Each one taught me something. Use the sidebar to jump directly " "to live dashboards or explore the overviews below." ) # Project definitions PROJECTS: list[dict[str, Any]] = [ { "title": "Toronto Housing Market Dashboard", "type": "Personal Project", "status": "Live", "status_color": "green", "problem": ( "Toronto's housing market moves fast, and most publicly available data " "is either outdated, behind paywalls, or scattered across dozens of sources. " "I wanted a single dashboard that tracked trends in real-time." ), "built": [ "Data Pipeline: Python scraper pulling listings data, automated on schedule", "Transformation Layer: dbt-based SQL architecture (staging -> intermediate -> marts)", "Visualization: Interactive Plotly-Dash dashboard with filters by neighborhood, price range, property type", "Infrastructure: PostgreSQL backend, version-controlled in Git", ], "tech_stack": "Python, dbt, PostgreSQL, Plotly-Dash, GitHub Actions", "learned": ( "Real estate data is messy as hell. Listings get pulled, prices change, " "duplicates are everywhere. Building a reliable pipeline meant implementing " 'serious data quality checks and learning to embrace "good enough" over "perfect."' ), "dashboard_link": "/toronto", "repo_link": "https://github.com/leomiranda/personal-portfolio", }, { "title": "US Retail Energy Price Predictor", "type": "Personal Project", "status": "Coming Soon", "status_color": "yellow", "problem": ( "Retail energy pricing in deregulated US markets is volatile and opaque. " "Consumers and analysts lack accessible tools to understand pricing trends " "and forecast where rates are headed." ), "built": [ "Data Pipeline: Automated ingestion of public pricing data across multiple US markets", "ML Model: Price prediction using time series forecasting (ARIMA, Prophet, or similar)", "Transformation Layer: dbt-based SQL architecture for feature engineering", "Visualization: Interactive dashboard showing historical trends + predictions by state/market", ], "tech_stack": "Python, Scikit-learn, dbt, PostgreSQL, Plotly-Dash", "learned": ( "This showcases the ML side of my skillset—something the Toronto Housing " "dashboard doesn't cover. It also leverages my domain expertise from 5+ years " "in retail energy operations." ), "dashboard_link": None, "repo_link": None, }, { "title": "DataFlow Platform", "type": "Professional", "status": "Case Study Pending", "status_color": "gray", "problem": ( "When I joined Summitt Energy, there was no data infrastructure. " "Reports were manual. Insights were guesswork. I was hired to fix that." ), "built": [ "v1 (2020): Basic ETL scripts pulling Genesys Cloud data into MSSQL", "v2 (2021): Dimensional model (star schema) with fact/dimension tables", "v3 (2022): Python refactor with SQLAlchemy ORM, batch processing, error handling", "v4 (2023-24): dbt-pattern SQL views (staging -> intermediate -> marts), FastAPI layer, CLI tools", ], "tech_stack": "Python, SQLAlchemy, FastAPI, MSSQL, Power BI, Genesys Cloud API", "impact": [ "21 tables, 1B+ rows", "5,000+ daily transactions processed", "40% improvement in reporting efficiency", "30% reduction in call abandon rate", "50% faster Average Speed to Answer", ], "learned": ( "Building data infrastructure as a team of one forces brutal prioritization. " "I learned to ship imperfect solutions fast, iterate based on feedback, " "and never underestimate how long stakeholder buy-in takes." ), "note": "This is proprietary work. A sanitized case study with architecture patterns (no proprietary data) will be published in Phase 3.", "dashboard_link": None, "repo_link": None, }, { "title": "AI-Assisted Automation (Bandit Labs)", "type": "Consulting/Side Business", "status": "Active", "status_color": "blue", "problem": ( "Small businesses don't need enterprise data platforms—they need someone " "to eliminate the 4 hours/week they spend manually entering receipts." ), "built": [ "Receipt Processing Automation: OCR pipeline (Tesseract, Google Vision) extracting purchase data from photos", "Product Margin Tracker: Plotly-Dash dashboard with real-time profitability insights", "Claude Code Plugins: MCP servers for Gitea, Wiki.js, NetBox integration", ], "tech_stack": "Python, Tesseract, Google Vision API, Plotly-Dash, QuickBooks API", "learned": ( "Small businesses are underserved by the data/automation industry. " "Everyone wants to sell them enterprise software they don't need. " "I like solving problems at a scale where the impact is immediately visible." ), "dashboard_link": None, "repo_link": None, "external_link": "/lab", "external_label": "Learn More About Bandit Labs", }, ] def create_project_card(project: dict[str, Any]) -> dmc.Paper: """Create a detailed project card.""" # Build the "What I Built" list built_items = project.get("built", []) built_section = ( dmc.Stack( [ dmc.Text("What I Built:", fw=600, size="sm"), dmc.List( [dmc.ListItem(dmc.Text(item, size="sm")) for item in built_items], spacing="xs", size="sm", ), ], gap="xs", ) if built_items else None ) # Build impact section for DataFlow impact_items = project.get("impact", []) impact_section = ( dmc.Stack( [ dmc.Text("Impact:", fw=600, size="sm"), dmc.Group( [ dmc.Badge(item, variant="light", size="sm") for item in impact_items ], gap="xs", ), ], gap="xs", ) if impact_items else None ) # Build action buttons buttons = [] if project.get("dashboard_link"): buttons.append( dcc.Link( dmc.Button( "View Dashboard", variant="light", size="sm", leftSection=DashIconify(icon="tabler:chart-bar", width=16), ), href=project["dashboard_link"], ) ) if project.get("repo_link"): buttons.append( dmc.Anchor( dmc.Button( "View Repository", variant="subtle", size="sm", leftSection=DashIconify(icon="tabler:brand-github", width=16), ), href=project["repo_link"], target="_blank", ) ) if project.get("external_link"): buttons.append( dcc.Link( dmc.Button( project.get("external_label", "Learn More"), variant="outline", size="sm", leftSection=DashIconify(icon="tabler:arrow-right", width=16), ), href=project["external_link"], ) ) # Handle "Coming Soon" state if project["status"] == "Coming Soon" and not buttons: buttons.append( dmc.Badge("Coming Soon", variant="light", color="yellow", size="lg") ) return dmc.Paper( dmc.Stack( [ # Header dmc.Group( [ dmc.Stack( [ dmc.Text(project["title"], fw=600, size="lg"), dmc.Text(project["type"], size="sm", c="dimmed"), ], gap=0, ), dmc.Badge( project["status"], color=project["status_color"], variant="light", size="lg", ), ], justify="space-between", align="flex-start", ), # Problem dmc.Stack( [ dmc.Text("The Problem:", fw=600, size="sm"), dmc.Text(project["problem"], size="sm", c="dimmed"), ], gap="xs", ), # What I Built built_section, # Impact (if exists) impact_section, # Tech Stack dmc.Group( [ dmc.Text("Tech Stack:", fw=600, size="sm"), dmc.Text(project["tech_stack"], size="sm", c="dimmed"), ], gap="xs", ), # What I Learned dmc.Stack( [ dmc.Text("What I Learned:", fw=600, size="sm"), dmc.Text(project["learned"], size="sm", fs="italic"), ], gap="xs", ), # Note (if exists) ( dmc.Alert( project["note"], color="gray", variant="light", ) if project.get("note") else None ), # Action buttons dmc.Group(buttons, gap="sm") if buttons else None, ], gap="md", ), p="xl", radius="md", withBorder=True, ) layout = dmc.Container( dmc.Stack( [ dmc.Title("Projects", order=1, ta="center"), dmc.Text( INTRO_TEXT, size="md", c="dimmed", ta="center", maw=700, mx="auto" ), dmc.Divider(my="lg"), *[create_project_card(project) for project in PROJECTS], dmc.Space(h=40), ], gap="xl", ), size="md", py="xl", )