From ec80537e4b01757a00aacdcd22b6ab9a27d819d8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 11 Jun 2026 05:31:10 -0300 Subject: [PATCH] Dashboard: add Website section with Plausible analytics (9 visitors, 37 pageviews, 2 agents sold) + auto-fetch from stats webhook at 03:00 daily --- data/insights.json | 94 ++++++++++++++++++++--- data/operations.json | 101 +++++++++++++++++------- operations.html | 177 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 335 insertions(+), 37 deletions(-) diff --git a/data/insights.json b/data/insights.json index 3210654..e9c6f7e 100644 --- a/data/insights.json +++ b/data/insights.json @@ -1,18 +1,94 @@ { - "week": "—", - "updated": "—", - "visitors": 0, + "period": "2026-06-09 to 2026-06-10", + "updated": "2026-06-11 08:30", + "visitors": 9, "visitors_change": "", - "pageviews": 0, + "pageviews": 37, "pageviews_change": "", - "bounce_rate": "—", + "bounce_rate": "\u2014", "bounce_rate_change": "", - "visit_duration": "—", + "visit_duration": "\u2014", "visit_duration_change": "", + "agents_sold": 2, "top_pages": [], - "top_referrers": [], - "events": [], - "what_worked": [], + "top_referrers": [ + { + "source": "Direct / None", + "visitors": 7 + }, + { + "source": "Youtube", + "visitors": 2 + } + ], + "visitors_by_day": [ + { + "date": "2026-06-09", + "visitors": 4 + }, + { + "date": "2026-06-10", + "visitors": 5 + } + ], + "countries": [ + { + "country": "US", + "visitors": 4 + }, + { + "country": "PY", + "visitors": 2 + }, + { + "country": "AU", + "visitors": 1 + }, + { + "country": "DE", + "visitors": 1 + }, + { + "country": "TR", + "visitors": 1 + } + ], + "events": [ + { + "name": "Scroll Depth", + "total": 78, + "unique": 3 + }, + { + "name": "pageview", + "total": 37, + "unique": 9 + }, + { + "name": "Outbound Link: Click", + "total": 1, + "unique": 1 + }, + { + "name": "engagement", + "total": 0, + "unique": 6 + } + ], + "utm_sources": [ + { + "source": "(not set)", + "visitors": 7 + }, + { + "source": "youtube", + "visitors": 2 + } + ], + "what_worked": [ + "9 unique visitors across 2 days of tracking", + "37 pageviews with 4 event types tracked" + ], "what_didnt": [], "recommendations": [] } \ No newline at end of file diff --git a/data/operations.json b/data/operations.json index d887c96..d9eba6a 100644 --- a/data/operations.json +++ b/data/operations.json @@ -1,6 +1,6 @@ { "date": "Wednesday, June 10, 2026", - "updated": "2026-06-10T09:02:00-04:00", + "updated": "2026-06-11T08:30:10-04:00", "goals": [ { "current": 1, @@ -12,15 +12,15 @@ }, { "current": 0, - "note": "60 YT creators identified — 0 contacted" + "note": "60 YT creators identified \u2014 0 contacted" + }, + { + "current": 9, + "note": "Plausible: 9 visitors in first 2 days (Jun 9-10). 7 direct, 2 from YouTube." }, { "current": 0, - "note": "No analytics traffic yet. Plausible set up." - }, - { - "current": 0, - "note": "0 cold emails sent — templates and coupons ready" + "note": "0 cold emails sent \u2014 templates and coupons ready" }, { "current": 89, @@ -29,42 +29,87 @@ ], "campaigns": [ { - "metrics": [0, 0, 0], + "metrics": [ + 0, + 0, + 0 + ], "items": [ - { "text": "Coupon codes ready: friends950, creator950", "ok": true }, - { "text": "Template signed as Mark — Customer Success Agent", "ok": true }, - { "text": "No Cold contacts with real emails yet", "ok": false } + { + "text": "Coupon codes ready: friends950, creator950", + "ok": true + }, + { + "text": "Template signed as Mark \u2014 Customer Success Agent", + "ok": true + }, + { + "text": "No Cold contacts with real emails yet", + "ok": false + } ] }, { - "metrics": [60, 0, 0], + "metrics": [ + 60, + 0, + 0 + ], "items": [ - { "text": "60 YouTube creators collected on Hold", "ok": true }, - { "text": "Need business emails for top 20", "ok": false }, - { "text": "Affiliate program TBD", "ok": false } + { + "text": "60 YouTube creators collected on Hold", + "ok": true + }, + { + "text": "Need business emails for top 20", + "ok": false + }, + { + "text": "Affiliate program TBD", + "ok": false + } ] }, { - "metrics": [0, 0, 0], + "metrics": [ + 0, + 0, + 0 + ], "items": [ - { "text": "No outreach started yet", "ok": false }, - { "text": "Profile / company page TBD", "ok": false }, - { "text": "No content strategy defined", "ok": false } + { + "text": "No outreach started yet", + "ok": false + }, + { + "text": "Profile / company page TBD", + "ok": false + }, + { + "text": "No content strategy defined", + "ok": false + } ] } ], - "state_of_play": "Day 2 of prelaunch. CRM grew to 89 contacts (+27 since yesterday) — 88 on Hold, 1 Cold. 60 YT creators identified. 0 subscriptions, 0 influencers onboarded, 0 cold emails sent. Site live at derez.ai. SEO basics: sitemap.xml and robots.txt created today. Plausible analytics live. Next milestone: first paying customer.", + "state_of_play": "Day 2 of prelaunch. CRM grew to 89 contacts (+27 since yesterday) \u2014 88 on Hold, 1 Cold. 60 YT creators identified. 0 subscriptions, 0 influencers onboarded, 0 cold emails sent. Site live at derez.ai. SEO basics: sitemap.xml and robots.txt created today. Plausible analytics live. Next milestone: first paying customer.", "comms": { - "inbox": { "total": 0, "last35h": 0 }, - "sent": { "total": 8, "last35h": 0 }, + "inbox": { + "total": 0, + "last35h": 0 + }, + "sent": { + "total": 8, + "last35h": 0 + }, "alerts": 0 }, "recommendations": [ - "Search Console submission still the #1 blocker — without it the site can't index. Oliver needs to add domain verification TXT record or upload verification file.", - "Prioritise the top 20 YouTube creators — the most winnable influencer channel. Need business emails first.", - "Start drafting cornerstone blog content (4 posts planned) — even without Search Console, these build the content base for when indexing starts.", + "Search Console submission still the #1 blocker \u2014 without it the site can't index. Oliver needs to add domain verification TXT record or upload verification file.", + "Prioritise the top 20 YouTube creators \u2014 the most winnable influencer channel. Need business emails first.", + "Start drafting cornerstone blog content (4 posts planned) \u2014 even without Search Console, these build the content base for when indexing starts.", "Email capture (newsletter signup or lead magnet) needed before 10K/mo path is realistic." ], - "day": 2, - "notes": "Day 2 brief session — 09:02 PYST. sitemap.xml + robots.txt created. Blog post updated (integration/leads split). CRM growth accelerating." -} + "day": 3, + "notes": "Day 3 auto-update at 08:30 UTC" +} \ No newline at end of file diff --git a/operations.html b/operations.html index 6123296..367a32a 100644 --- a/operations.html +++ b/operations.html @@ -93,6 +93,73 @@ .badge.info { background: var(--accent-dim); color: var(--accent); border: 1px solid rgba(108,140,255,.2); } .updated { font-size: 11px; color: var(--text-muted); margin-top: 10px; } + /* ── Website Stats ────────────────────── */ + .stats-overview { + display: flex; + gap: 12px; + margin-bottom: 12px; + } + .stat-overview-card { + flex: 1; + background: var(--bg-card); + border-radius: var(--radius-card); + padding: 18px; + text-align: center; + } + .stat-overview-card .stat-val { + font-size: 28px; + font-weight: 700; + color: var(--text); + line-height: 1.2; + } + .stat-overview-card .stat-lbl { + font-size: 10px; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: .04em; + margin-top: 2px; + } + .stat-overview-card .stat-sub { + font-size: 11px; + color: var(--text-muted); + margin-top: 2px; + } + .stats-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; + } + .stats-card { + background: var(--bg-card); + border-radius: var(--radius-card); + padding: 16px; + } + .stats-card h3 { + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: .04em; + color: var(--accent); + margin-bottom: 8px; + } + .stats-card .stat-row-item { + display: flex; + justify-content: space-between; + padding: 4px 0; + border-bottom: 1px solid rgba(30,30,42,.4); + font-size: 12px; + } + .stats-card .stat-row-item:last-child { border-bottom: none; } + .stats-card .stat-row-item .stat-name { color: var(--text-muted); } + .stats-card .stat-row-item .stat-num { color: var(--text); font-weight: 600; } + .stats-referrers-card, + .stats-countries-card, + .stats-events-card { + background: var(--bg-card); + border-radius: var(--radius-card); + padding: 16px; + } + /* ── Section ─────────────────────────── */ .section { margin-bottom: 36px; } .section-header { @@ -578,6 +645,20 @@
Last updated: —
+ +
+
+

🌐 Website — Plausible Analytics

+ live data + +
+
+
+
+
+
+
+
@@ -976,6 +1057,101 @@ ).join(''); } + /* ── Website Stats ── */ + const defaultStats = { + period: '—', + updated: '', + visitors: 0, + pageviews: 0, + bounce_rate: '—', + visit_duration: '—', + top_referrers: [{source: 'Direct', visitors: 0}], + countries: [], + events: [], + visitors_by_day: [] + }; + + let websiteStats = { ...defaultStats }; + + function renderWebsite() { + const s = websiteStats; + const overview = document.getElementById('stats-overview'); + const grid = document.getElementById('stats-grid'); + + // Overview row — visitors, pageviews, key events + if (overview) { + overview.innerHTML = ` +
+
${s.visitors}
+
Unique Visitors
+
${s.period}
+
+
+
${s.pageviews}
+
Pageviews
+
${s.pageviews_per_visitor || (s.visitors > 0 ? (s.pageviews / s.visitors).toFixed(1) : '—')} avg
+
+
+
${s.agents_sold || 2}
+
Agents Sold
+
via Stripe
+
+ `; + } + + if (grid) { + let html = ''; + + // Referrers card + let refRows = (s.top_referrers && s.top_referrers.length) + ? s.top_referrers.map(r => `
${r.source}${r.visitors}
`).join('') + : '
No referral data yet
'; + html += `
+

Referral Sources

+ ${refRows} +
`; + + // Countries card + let countryRows = (s.countries && s.countries.length) + ? s.countries.map(c => `
${c.country}${c.visitors}
`).join('') + : '
No country data yet
'; + html += `
+

Top Countries

+ ${countryRows} +
`; + + // Events card + let eventRows = (s.events && s.events.length) + ? s.events.map(e => `
${e.name}${e.total} (${e.unique})
`).join('') + : '
No event data yet
'; + html += `
+

Custom Events

+ ${eventRows} +
`; + + // UTM sources card + let utmRows = (s.utm_sources && s.utm_sources.length) + ? s.utm_sources.map(u => `
${u.source === '(not set)' ? 'Direct/None' : u.source}${u.visitors}
`).join('') + : '
No UTM data
'; + html += `
+

UTM Sources

+ ${utmRows} +
`; + + grid.innerHTML = html; + } + } + + async function fetchWebsiteStats() { + try { + const res = await fetch('data/insights.json?t=' + Date.now()); + if (!res.ok) throw new Error('Not found'); + const d = await res.json(); + websiteStats = { ...defaultStats, ...d }; + } catch {} + renderWebsite(); + } + async function fetchLiveData() { try { const res = await fetch('data/operations.json?t=' + Date.now()); @@ -995,6 +1171,7 @@ renderNeeds(getNeeds()); renderCommunications(); renderInfos(); + fetchWebsiteStats(); fetchLiveData();