Your Fractional C-Suite, Powered by AI

12 expert agents with 200+ skills. Running 24/7 on local compute. Built for South African business.

12
Expert Agents
200+
Skills
8
Domains
R0
Per Query

Meet Your Team

Each agent is grounded in domain expertise — not generic chat. They know SA regulations, local suppliers, and your market context.

See all 12 agents →


What They Actually Produce

Real deliverables generated by AI agents with skill-grounded expertise. Not generic advice — actionable work product.

data alex

Data Warehouse Architecture

This is a classic warehousing challenge that requires a structured approach integrating OLTP data into an analytical (OLAP) structure. Since you are dealing with time-series transactional data (sales/...

Read full response

Prompt: We have 3 years of transactional data in PostgreSQL (50M rows). Design a data warehouse architecture for customer LTV analysis, churn prediction, and cohort analysis. Include the dimensional model with specific fact and dimension tables.

This is a classic warehousing challenge that requires a structured approach integrating OLTP data into an analytical (OLAP) structure. Since you are dealing with time-series transactional data (sales/behavior), the Star Schema built around a Fact Table and supporting Dimension Tables is the industry standard and most efficient pattern for this analysis.


Given the scope (LTV, Cohorting), we will need robust dimensionality, particularly around time and customer identity.


Here is the complete architecture proposal, broken down by components and implementation details.


---


📊 Proposed Architecture: Star Schema


The goal is to analyze what happened (Facts) to whom (Dimensions) and when (Dimensions) over time.


1. Core Components


  • Fact Table: Records the quantifiable events (transactions, usage). This will be the largest table.
  • Dimension Tables (The "Who, What, Where, When"): Provide the context and descriptive attributes for the facts.
  • Data Warehouse (Target): A dedicated, append-only system (e.g., Snowflake, Redshift, BigQuery) optimized for read concurrency.

2. Schema Diagram Concept


(Imagine a central table linking to surrounding rectangular descriptor tables)


$$\text{Fact\_Fact\_Sales}$$

$$\text{/ | \ \ | \ }$$

$$\text{Dim\_Date} \rightarrow \text{Dim\_Customer} \rightarrow \text{Dim\_Product} \rightarrow \text{Dim\_Promotion}$$


---


🧩 Detailed Table Definitions


A. 🌐 Dimension Tables (The Context)


Dimension tables are relatively stable and describe the entities involved. You will use Surrogate Keys (surrogate keys, e.g., date_key, customer_key) in these tables, which are integers, to link to the Fact Table.


1. Dim_Date (The Time Dimension - CRITICAL)

This table must be pre-populated with every date you expect to analyze.

  • date_key (Primary Key, e.g., YYYYMMDD)
  • full_date (DATE type)
  • day_of_week (VARCHAR, e.g., 'Wednesday')
  • day_number (INT, 1-31)
  • month (INT, 1-12)
  • month_name (VARCHAR)
  • quarter (VARCHAR, e.g., 'Q2')
  • year (INT)

2. Dim_Customer (The Who Dimension - CRITICAL)

This handles customer attributes. Use SCD Type 2 logic here if customer attributes change over time (e.g., "Customer changed subscription tier from Bronze to Silver").

  • customer_key (Primary Key, Surrogate Key, INT)
  • customer_id (Natural Key, from Source System, VARCHAR)
  • first_name, last_name (VARCHAR)
  • acquisition_date (DATE)
  • acquisition_channel (VARCHAR)
  • is_active (BOOLEAN)
  • SCD Type 2 Attributes: valid_from_date, valid_to_date (To track historical attributes)

3. Dim_Product (The What Dimension)

Describes what was sold or used.

  • product_key (Primary Key, Surrogate Key, INT)
  • product_id (Natural Key, from Source System, VARCHAR)
  • product_name (VARCHAR)
  • category (VARCHAR, e.g., 'Electronics')
  • subcategory (VARCHAR)
  • brand (VARCHAR)

4. Dim_Promotion (The How Dimension)

Describes any discount or campaign that impacted the transaction.

  • promotion_key (Primary Key, Surrogate Key, INT)
  • promo_code (Natural Key, VARCHAR)
  • promotion_type (VARCHAR, e.g., 'Percentage Off', 'BOGO')
  • description (VARCHAR)

---


B. 🔢 Fact Table (The Measurements)


The Fact table records every measurable event. Since you are tracking transactions, this will be a Transactional Fact Table.


Fact_Sales

  • sales_key (Primary Key, Identity, BIGINT)
  • Foreign Keys (Links to Dimensions):
  • date_key (FK to Dim_Date)
  • customer_key (FK to Dim_Customer)
  • product_key (FK to Dim_Product)
  • promotion_key (FK to Dim_Promotion, can be NULL if no promo)
  • Measures (The Metrics): These are the numbers you aggregate.
  • quantity_sold (INT)
  • unit_price (DECIMAL)
  • extended_price (DECIMAL) (Quantity * Unit Price)
  • discount_amount (DECIMAL)
  • net_sales_amount (DECIMAL) (The actual monetary value recorded for LTV calculation)

---


✨ How This Schema Answers Your Business Questions


| Business Question | Required Calculation Path | Relevant Tables |

| :--- | :--- | :--- |

| Customer LTV | Sum of net_sales_amount over time, grouped by customer_key. | Fact_Sales $\rightarrow$ Dim_Customer |

| Cohort Analysis | Grouping events by the date_key when the customer was first acquired (Dim_Customer.acquisition_date). | Dim_Customer.acquisition_date $\rightarrow$ Fact_Sales Grouped by Cohort Year/Month |

| Best Selling Products | Sum of quantity_sold or net_sales_amount, grouped by product_key. | Fact_Sales $\rightarrow$ Dim_Product |

| Monthly Performance | Aggregating metrics by date_key attributes (Year, Month, Quarter). | Fact_Sales $\rightarrow$ Dim_Date |

| Promo Impact | Analyzing net sales amount, filtered by a specific promotion_key. | Fact_Sales $\rightarrow$ Dim_Promotion |


---


🛠️ ETL/ELT Considerations (The Process)


This architecture requires an Extract, Transform, Load (ETL/ELT) process:


  • Extraction: Pull raw data from operational systems (e.g., Sales_Transactions table, Customer_CRM table).
  • Transformation (The Key Steps):
  • Dimension Population: Routinely update Dim_Product and Dim_Date. For Dim_Customer, implement SCD Type 2 logic for critical attributes.
  • Key Lookup: For every raw transaction record, you must look up the correct Surrogate Key (date_key, customer_key, etc.) using the natural keys found in the raw data.
  • Fact Loading: Construct the row in Fact_Sales using the loaded surrogate keys and the calculated measures.
  • Loading: Append the transformed, structured data into the respective warehouse tables.

💡 Summary Checklist


  • Schema: Star Schema is optimal.
  • Keys: Use Surrogate Keys (Integers) in the Fact table for performance.
  • Time: A dedicated, pre-built Dim_Date is mandatory for time-series analysis.
  • Complexity: Pay special attention to SCD Type 2 for the Dim_Customer table to accurately model changing customer profiles over their lifetime.
gemma4:e4b 75.6s 5,828 tokens
data alex

dbt Project Structure

This is a comprehensive setup for a standard Kimball-style data warehouse architecture, using the modern `dbt` workflow. We will define the structure, and then supply the code examples for the key co...

Read full response

Prompt: Set up a dbt project structure for our e-commerce analytics. We need staging, intermediate, and mart layers. Show me the folder structure, YAML config, and SQL for a customer lifetime value mart model.

This is a comprehensive setup for a standard Kimball-style data warehouse architecture, using the modern dbt workflow.


We will define the structure, and then supply the code examples for the key components: Staging (stg_), Intermediate (int_), and Final Mart (marts/dim_... and marts/fct_...).


---


1. Target Schema Structure


Assuming the following source data tables exist in your raw schema (e.g., in Snowflake/BigQuery):


  • raw.orders: Transactional order details.
  • raw.customers: Customer profiles.
  • raw.products: Product catalog details.

Your compiled dbt project structure should look like this:


``

your_dbt_project/

├── models/

│ ├── staging/ # 1. Staging Layer (Clean, minimal transformation)

│ │ ├── stg_customers.sql

│ │ ├── stg_orders.sql

│ │ └── stg_products.sql

│ ├── intermediate/ # 2. Intermediate Layer (Join staging data, calculate metrics)

│ │ ├── int_customer_agg.sql

│ │ ├── int_order_details.sql

│ │ └── int_order_line_items.sql

│ └── marts/ # 3. Mart Layer (Final, consumable dimensional/fact tables)

│ ├── dim_customer.sql # Dimension Table

│ ├── dim_product.sql # Dimension Table

│ └── fct_orders.sql # Fact Table (Final Grain)

├── dbt_project.yml # Project configuration

└── profiles.yml # Connection configuration (handled by CLI)

`


---


2. Step-by-Step Model Code


A. Staging Layer (staging/)


Goal: Select only necessary columns, apply basic type casting, and standardize names. No heavy logic here.


models/staging/stg_customers.sql

`sql

{{ config(materialized='view') }}


SELECT

customer_id,

first_name,

last_name,

email,

created_at AS customer_signup_date,

-- Example of cleaning/standardizing messy data

UPPER(coalesce(country, 'UNKNOWN')) AS standard_country

FROM

{{ source('raw', 'customers') }}

`


B. Intermediate Layer (intermediate/)


Goal: Perform first-level joins and complex metric calculations that will feed the final marts.


models/intermediate/int_order_line_items.sql

`sql

{{ config(materialized='view') }}


SELECT

o.order_id,

o.customer_id,

o.order_date,

p.product_id,

p.product_name,

p.category,

o.quantity,

o.unit_price,

(o.quantity * o.unit_price) AS line_item_revenue -- Calculated metric

FROM

{{ ref('stg_orders') }} o

INNER JOIN

{{ ref('stg_products') }} p ON o.product_id = p.product_id

`


C. Mart Layer (marts/)


This is what the end-user/BI tool connects to. We'll implement a Slowly Changing Dimension (SCD) Type 1 for customers and a Fact Table for orders.


1. Dimension: Customer (models/marts/dim_customer.sql)

We use incremental here as customer data might change slightly over time.


`sql

{{ config(

materialized='incremental',

unique_key='customer_id',

incremental_strategy='merge' -- Best practice for SCD 1/2

) }}


SELECT

c.customer_id,

-- SCD Type 1 Logic: Overwrite on change

c.first_name,

c.last_name,

c.email,

c.standard_country,

c.customer_signup_date,

CURRENT_TIMESTAMP() AS dbt_loaded_at -- Audit column

FROM

{{ ref('stg_customers') }} c


{% if is_incremental() %}

-- Only process records newer than the last run

WHERE c.customer_signup_date > (SELECT MAX(dbt_loaded_at) FROM {{ this }})

{% endif %}

`


2. Fact: Orders (models/marts/fct_orders.sql)

This table typically joins dimensions to the transaction facts.


`sql

{{ config(

materialized='incremental',

unique_key='order_id',

incremental_strategy='merge'

) }}


SELECT

o.order_id,

o.order_date,

-- Foreign Keys (linking to Dimensions)

c_dim.customer_id AS customer_fk,

p_dim.product_id AS product_fk,


-- Facts/Metrics

o.quantity,

o.unit_price,

o.line_item_revenue,


-- Date Dimension Keys (if you build a full dedicated date dimension)

-- DATE_DAY(o.order_date) AS date_key

FROM

{{ ref('int_order_line_items') }} o

INNER JOIN

{{ ref('dim_customer') }} c_dim ON o.customer_id = c_dim.customer_id

{# Add other dimension joins here #}


{% if is_incremental() %}

-- Only process orders placed since the last run

WHERE o.order_date > (SELECT MAX(order_date) FROM {{ this }})

{% endif %}

`


---


3. Execution Summary


Required Configurations


  • dbt_project.yml: You must define your sources so dbt knows where raw. tables are.

`yaml

models/dbt_project.yml

name: 'my_data_warehouse'

version: '1.0.0'

profile: 'default' # Must match your CLI profile

sources:

  • name: raw

database: your_raw_database

schema: raw_schema # Schema where raw tables live

tables:

  • name: customers
  • name: orders
  • name: products

`


  • Run Order: Because of the {{ ref(...) }} function, dbt automatically figures out the dependency graph. You run:
  • dbt run

Execution Flow Achieved by dbt


  • Staging: stg_customers reads from raw.customers.
  • Intermediate: int_order_line_items reads from stg_orders and stg_products.
  • Dimension: dim_customer reads from stg_customers.
  • Fact: fct_orders reads from int_order_line_items and then joins to the newly created/updated dim_customer` table.

This provides a clean, reproducible, and scalable data modeling pipeline.

gemma4:e4b 67.1s 5,724 tokens
data alex

ML Problem Framing

This is a classic and high-value Machine Learning problem. Since the goal is to predict **customer attrition (churn)**, the output will be a **classification problem**. Here is a comprehensive framew...

Read full response

Prompt: We want to predict customer churn for our SaaS platform. We have 18 months of usage data, payment history, and support tickets. Frame this as an ML problem: target variable, features, model selection, and how to measure success.

This is a classic and high-value Machine Learning problem. Since the goal is to predict customer attrition (churn), the output will be a classification problem.


Here is a comprehensive framework for structuring this project, from problem definition to deployment considerations.


---


🎯 Phase 1: Problem Framing & Goal Setting


1. Define Churn

The most critical step is defining what "churn" means operationally.


  • Definition: A customer is considered "churned" if they exhibit one or more of the following behaviors within a defined look-back period (e.g., 30, 60, or 90 days):
  • No logins for $X$ consecutive days.
  • No product usage (key feature $Y$) for $X$ consecutive days.
  • Has not made a purchase/upsell within $Y$ months.
  • Target Variable ($Y$): A binary flag (0 or 1). $Y=1$ if the customer churns within the specified prediction window post-snapshot date; $Y=0$ otherwise.

2. Define the Prediction Time Horizon

  • Snapshot Date ($T_{snapshot}$): The day you take the data snapshot to generate feature vectors.
  • Prediction Window: You want to predict if they will churn in the next $W$ days (e.g., next 60 days).
  • Formula: Features are calculated using data up to $T_{snapshot}$. The model predicts the value of $Y$ between $T_{snapshot}$ and $T_{snapshot} + W$.

3. Business Goal & Metrics

The success of the model isn't just high accuracy; it must drive revenue action.


  • Primary Objective: Maximize the identification of high-value, high-risk churners.
  • Key Metric: Area Under the ROC Curve (AUC) for model evaluation, as it measures discriminative power across all possible thresholds.
  • Business Metric: Precision-Recall Curve (PR-AUC), especially important if churn is rare (class imbalance).
  • Operational Metric: Recall on High-Value Customers (HVCs): We want to catch as many true positives among our biggest spenders as possible ($\text{Maximize True Positives} / \text{Total Actual Positives}$).

---


📊 Phase 2: Feature Engineering (The Core)


Features must capture changes in customer behavior, not just static facts. These fall into several behavioral buckets.


1. Usage/Engagement Features (Recency, Frequency, etc. - RFM-like)

These quantify how and how often the customer uses the product.


  • Recency: Days since last login, days since last key action.
  • Frequency: Average logins per week over the last 3 months.
  • Depth/Breadth: Number of unique features used (Breadth); average number of actions per session (Depth).
  • Velocity: Change in usage rate (e.g., Usage rate over last 30 days vs. usage rate over 90-120 days). A declining velocity is a strong predictor.

2. Subscription/Billing Features

Static and transactional data related to the contract.


  • Time since last billing change/upgrade.
  • Plan type (Tier 1, Enterprise, etc.).
  • Contract length remaining.
  • Number of users/seats purchased.

3. Customer Service/Support Features

Indicates friction points.


  • Number of support tickets opened in the last 90 days.
  • Average time to resolution (TTR) for support tickets.
  • Number of times the customer contacted support for the same issue (Repetitive Friction).

4. Product Adoption/Feature Success Features

Does the customer adopt the "sticky" features?


  • Adoption rate of key features (e.g., Did they use Feature X? $\frac{0 \text{ or } 1}{\text{Total Features}}$).
  • Use of high-impact features (e.g., Reporting dashboard, API integration).

Handling Imbalance

Churn is usually rare (e.g., 5-10% churn rate). Your dataset will be highly imbalanced.


  • Mitigation Strategies:
  • Use models sensitive to imbalance (e.g., XGBoost, LightGBM).
  • Use weighting techniques during training (assigning higher penalty loss to misclassifying the minority class).
  • Sampling (SMOTE or Oversampling the minority class).

---


🧠 Phase 3: Model Selection & Training


1. Baseline Model

Start with a simple Logistic Regression model. This provides feature importance coefficients that are highly interpretable ("For every extra logged-in day, the odds of churn decrease by X%").


2. Advanced Models (Recommended)

  • Gradient Boosting Machines (XGBoost / LightGBM): These are generally the best performers for tabular classification data like this. They handle non-linear relationships and complex feature interactions very well.

3. Model Interpretation (Crucial for Action)

Once the best model is selected, do not just trust the black box. You must know why it predicts churn.


  • Feature Importance: Use built-in feature importance scores from XGBoost or SHAP (SHapley Additive exPlanations) values.
  • Actionable Insight: If SHAP reveals that declining usage velocity is the top predictor, the mitigation strategy is clear: "Increase engagement in the first 30 days to prevent velocity decay."

---


🚀 Phase 4: Deployment & Actionability (Operationalizing)


The project fails if the model is just a Jupyter Notebook file.


1. Scoring Pipeline

The model must be retrained regularly (e.g., weekly or monthly) using the latest data to capture changing market dynamics.


2. Risk Segmentation & Triage

Instead of treating all high-risk customers equally, segment the output:


| Segment | Risk Score Range | Value Status | Recommended Action |

| :--- | :--- | :--- | :--- |

| Red Alert | High (> 0.7) | High Value | Proactive outreach from Account Executive (AE), specialized tutorial, Executive check-in. |

| Amber Alert | Medium (0.3 - 0.7) | Medium/High | Automated email sequence, usage campaign offering, in-app guidance. |

| Green | Low (< 0.3) | Low Value | Monitoring only (Minimal resource expenditure). |

| False Positive | Low Model Score, High Support Cost | N/A | Process review (Did we misclassify an edge case?). |


Summary Table for Quick Reference


| Aspect | Consideration | Why it matters |

| :--- | :--- | :--- |

| Problem Type | Binary Classification | Predicting Yes/No (Churn/Stay) |

| Key Metrics | AUC, Recall (for HVCs) | Focus on catching valuable stragglers. |

| Feature Focus | Behavioral Change (Velocity) | Static data is weak; trends predict failure. |

| Best Model | XGBoost/LightGBM | Superior handling of complex, non-linear interactions. |

| Output Action | Risk Segmentation (Red/Amber) | Ensures sales/success teams focus effort where it matters most. |

gemma4:e4b 67.7s 5,742 tokens

Browse all 174 deliverables →


How Is This Different From ChatGPT?

A chatbot answers questions. An agent does work. The difference is defined skills, persistent memory, and tool access.

ChatGPT Plus
$20/month
Generic, data leaves SA
Claude Pro
$20/month
No domain grounding
2nth.ai Agents
R0/query
Skill-grounded, local, POPIA-safe

Learn how it works →

See What Your Team Can Do

Browse real deliverables from each agent — marketing plans, financial models, legal analysis, IoT specifications, and more.

View Showcase