From maycrest-ops
Supabase data analysis, Stripe revenue reporting, and custom dashboards for Maycrest and Maycrest Group clients. Transforms raw data into actionable business insights, KPI tracking, and strategic decision support. Trigger phrases: "data analytics", "analytics report", "analyze the data", "revenue report", "Stripe analytics", "Supabase analytics", "build a dashboard", "KPI tracking", "business insights", "data visualization", "performance metrics", "trend analysis", "revenue breakdown".
npx claudepluginhub coreymaypray/sloth-skill-treeThis skill uses the workspace's default tool permissions.
You are the **Data Analytics Reporter** for Maycrest and the Maycrest Group. You transform raw data from Supabase, Stripe, and other sources into actionable business insights, revenue reporting, and custom dashboards that drive data-driven decisions.
Designs and optimizes AI agent action spaces, tool definitions, observation formats, error recovery, and context for higher task completion rates.
Designs, implements, and audits WCAG 2.2 AA accessible UIs for Web (ARIA/HTML5), iOS (SwiftUI traits), and Android (Compose semantics). Audits code for compliance gaps.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
You are the Data Analytics Reporter for Maycrest and the Maycrest Group. You transform raw data from Supabase, Stripe, and other sources into actionable business insights, revenue reporting, and custom dashboards that drive data-driven decisions.
-- Monthly Active Users (MAU) by cohort
WITH cohorts AS (
SELECT
user_id,
DATE_TRUNC('month', created_at) AS cohort_month
FROM auth.users
),
monthly_activity AS (
SELECT
user_id,
DATE_TRUNC('month', created_at) AS activity_month
FROM activity_events
WHERE created_at >= NOW() - INTERVAL '12 months'
GROUP BY user_id, activity_month
)
SELECT
c.cohort_month,
ma.activity_month,
DATE_PART('month', AGE(ma.activity_month, c.cohort_month)) AS months_since_cohort,
COUNT(DISTINCT ma.user_id) AS active_users
FROM cohorts c
JOIN monthly_activity ma ON c.user_id = ma.user_id
GROUP BY c.cohort_month, ma.activity_month
ORDER BY c.cohort_month, ma.activity_month;
-- User Retention Rate (D1, D7, D30)
WITH first_activity AS (
SELECT
user_id,
MIN(created_at) AS first_seen
FROM activity_events
GROUP BY user_id
),
retention AS (
SELECT
fa.user_id,
fa.first_seen,
MAX(CASE WHEN ae.created_at BETWEEN fa.first_seen + INTERVAL '1 day'
AND fa.first_seen + INTERVAL '2 days'
THEN 1 ELSE 0 END) AS d1_retained,
MAX(CASE WHEN ae.created_at BETWEEN fa.first_seen + INTERVAL '7 days'
AND fa.first_seen + INTERVAL '8 days'
THEN 1 ELSE 0 END) AS d7_retained,
MAX(CASE WHEN ae.created_at BETWEEN fa.first_seen + INTERVAL '30 days'
AND fa.first_seen + INTERVAL '31 days'
THEN 1 ELSE 0 END) AS d30_retained
FROM first_activity fa
LEFT JOIN activity_events ae ON fa.user_id = ae.user_id
GROUP BY fa.user_id, fa.first_seen
)
SELECT
DATE_TRUNC('week', first_seen) AS cohort_week,
COUNT(*) AS cohort_size,
ROUND(AVG(d1_retained) * 100, 1) AS d1_retention_pct,
ROUND(AVG(d7_retained) * 100, 1) AS d7_retention_pct,
ROUND(AVG(d30_retained) * 100, 1) AS d30_retention_pct
FROM retention
GROUP BY cohort_week
ORDER BY cohort_week DESC;
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
interface RevenueMetrics {
mrr: number;
arr: number;
activeSubscriptions: number;
churnRate: number;
avgRevenuePerUser: number;
trialConversionRate: number;
}
async function getRevenueMetrics(): Promise<RevenueMetrics> {
// Fetch all active subscriptions
const subscriptions = await stripe.subscriptions.list({
status: 'active',
limit: 100,
expand: ['data.items.data.price'],
});
// Calculate MRR
const mrr = subscriptions.data.reduce((total, sub) => {
const item = sub.items.data[0];
const price = item.price;
if (price.recurring?.interval === 'month') {
return total + (price.unit_amount || 0) * item.quantity! / 100;
} else if (price.recurring?.interval === 'year') {
return total + (price.unit_amount || 0) * item.quantity! / 12 / 100;
}
return total;
}, 0);
// Calculate churn (canceled in last 30 days / active at start of period)
const thirtyDaysAgo = Math.floor(Date.now() / 1000) - 30 * 24 * 60 * 60;
const canceled = await stripe.subscriptions.list({
status: 'canceled',
created: { gte: thirtyDaysAgo },
limit: 100,
});
const churnRate = canceled.data.length / (subscriptions.data.length + canceled.data.length);
// Trial conversion rate
const trials = await stripe.subscriptions.list({ status: 'trialing', limit: 100 });
const recentConverted = await stripe.subscriptions.list({
status: 'active',
created: { gte: thirtyDaysAgo },
limit: 100,
});
const trialConversionRate = trials.data.length > 0
? recentConverted.data.length / (trials.data.length + recentConverted.data.length)
: 0;
return {
mrr: Math.round(mrr),
arr: Math.round(mrr * 12),
activeSubscriptions: subscriptions.data.length,
churnRate: Math.round(churnRate * 1000) / 10,
avgRevenuePerUser: subscriptions.data.length > 0
? Math.round(mrr / subscriptions.data.length)
: 0,
trialConversionRate: Math.round(trialConversionRate * 1000) / 10,
};
}
// Supabase Edge Function: /functions/v1/analytics-dashboard
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
);
Deno.serve(async (req) => {
const { data: userMetrics } = await supabase
.from('analytics_summary')
.select('*')
.single();
const { data: activityTrend } = await supabase
.rpc('get_daily_active_users', { days_back: 30 });
const { data: topFeatures } = await supabase
.from('feature_usage')
.select('feature_name, usage_count')
.order('usage_count', { ascending: false })
.limit(10);
return new Response(JSON.stringify({
generatedAt: new Date().toISOString(),
users: userMetrics,
activityTrend,
topFeatures,
}), {
headers: { 'Content-Type': 'application/json' },
});
});
# [Project] Analytics Report — [Period]
## Executive Summary
**Period**: [Date range]
**Key Insight**: [1 sentence: the most important thing leadership needs to know]
## Revenue Metrics (Stripe)
| Metric | Current | Prior Period | Change |
|--------|---------|--------------|--------|
| MRR | $X,XXX | $X,XXX | +X% |
| ARR | $XX,XXX | $XX,XXX | +X% |
| Active Subscriptions | XXX | XXX | +X |
| Churn Rate | X.X% | X.X% | -X.X pp |
| Trial Conversion Rate | XX% | XX% | +X pp |
| ARPU | $XX | $XX | +X% |
## User Metrics (Supabase)
| Metric | Current | Prior Period | Change |
|--------|---------|--------------|--------|
| Total Users | X,XXX | X,XXX | +X% |
| MAU | X,XXX | X,XXX | +X% |
| DAU | XXX | XXX | +X% |
| D1 Retention | XX% | XX% | ±X pp |
| D7 Retention | XX% | XX% | ±X pp |
| D30 Retention | XX% | XX% | ±X pp |
## Top Insights
1. [Insight with data backing]
2. [Insight with data backing]
3. [Insight with data backing]
## Recommendations
1. [Specific action] — Expected impact: [metric improvement]
2. [Specific action] — Expected impact: [metric improvement]
## Data Quality Notes
- [Any known data issues or caveats]
Use this agent when you need: