End-to-end web application development workflow with brand theming and standard patterns
Project Context — Read
project-config.mdin the repo root for brand tokens, shared-library paths, and deployment targets.
Invoke this skill when:
Every Streamlit page follows this mandatory template:
"""Page Title - Brief description of this page."""
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from src.components.shared_header import apply_page_config, render_header
# MUST be the FIRST Streamlit call
apply_page_config("PageName", "icon")
render_header(current_page="PageName")
# --- Page content below ---
Key Rules:
apply_page_config() MUST be the first Streamlit commandrender_header() with the current page nameExtract reusable UI elements into src/components/:
# src/components/kpi_cards.py
import streamlit as st
def render_kpi_row(kpis: list[dict]):
"""Render a row of KPI cards with brand theming."""
cols = st.columns(len(kpis))
for col, kpi in zip(cols, kpis):
with col:
st.metric(
label=kpi["label"],
value=kpi["value"],
delta=kpi.get("delta"),
)
# src/services/record_service.py
from loguru import logger
import pandas as pd
class RecordService:
def __init__(self, repository):
self._repo = repository
def get_dashboard_data(self, filter_type: str, date_str: str = "") -> dict:
"""Get all data needed for the dashboard page."""
logger.info(f"Loading dashboard data: filter={filter_type}, date={date_str}")
return {
"kpis": self._repo.get_kpi_summary(filter_type, date_str),
"trend": self._repo.get_trend_data(filter_type, date_str),
"distribution": self._repo.get_workbasket_distribution(filter_type, date_str),
}
# src/services/record_repository.py
import pandas as pd
from src.ingestion_config.data_sources import get_data_source_config
class RecordRepository:
def __init__(self):
self._config = get_data_source_config()
self._adapter = self._create_adapter()
def execute_query(self, query_name: str, **params) -> pd.DataFrame:
"""Execute a named query from queries.yaml."""
query_config = self._config.get_query(query_name)
sql = query_config["sql"].format(table=self._config.get_table(query_config["entity"]))
return self._adapter.fetch_dataframe(sql, params.get("params", []))
All SQL goes in src/ingestion_config/queries.yaml:
home_charts:
workbasket_distribution:
description: "Count open cases by workbasket for dashboard"
entity: pega_cases
sql: |
SELECT
ISNULL(WorkbasketHeading, 'Unknown') AS workbasket_heading,
COUNT(*) AS count
FROM {table}
WHERE [Created Date Time] >= ?
AND [Created Date Time] < ?
AND Status = 'Open'
GROUP BY WorkbasketHeading
ORDER BY count DESC
# Use brand color constants
BRAND_RED = "#E10A0A"
BRAND_NAVY = "#1F2937"
LIGHT_BG = "#F8F9FA"
CHART_COLORS = [BRAND_RED, BRAND_NAVY, "#6B7280", "#9CA3AF", "#D1D5DB"]
# Load CSS theme
def load_theme():
css_path = Path(__file__).parent.parent / "styles" / "theme.css"
if css_path.exists():
st.markdown(f"<style>{css_path.read_text()}</style>", unsafe_allow_html=True)
def init_session_state():
defaults = {
"authenticated": False,
"current_user": None,
"selected_filters": {},
"page_number": 1,
"filter_type": "daily",
}
for key, value in defaults.items():
if key not in st.session_state:
st.session_state[key] = value
def on_filter_change():
"""Reset pagination when filters change."""
st.session_state.page_number = 1
from datetime import timedelta
@st.cache_data(ttl=timedelta(minutes=15), show_spinner="Loading data...")
def load_dashboard_data(filter_type: str, date_str: str) -> dict:
service = RecordService(get_repo())
return service.get_dashboard_data(filter_type, date_str)
@st.cache_resource
def get_repo():
return RecordRepository()
from loguru import logger