prelaunch: create launch dashboard + daily cron updates
- New launch-dashboard.html: KPI grid, 14-day action plan, strategy
overview, items-needed checklist, daily routine, cron schedule
- Nav link '🚀 Launch' added to main site header
- data/launch-status.json: data file updated daily at 03:00 by cron
- scripts/update-dashboard.py: advances day, probes KPIs, marks
today's actions
- cron jobs configured:
• 03:00 daily — dashboard update script + git commit/push
• 09:00 daily — 1-hour working session reminder
This commit is contained in:
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Daily launch dashboard updater — runs at 03:00 PYST via cron.
|
||||
|
||||
Reads data/launch-status.json, updates KPIs from live sources,
|
||||
advances the day counter, sets today's actions to 'today' status,
|
||||
and writes back. Designed to be quiet (stdout only on error) so cron
|
||||
delivery stays clean.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import date, datetime, timezone, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
HERE = Path(__file__).resolve().parent.parent # repo root (scripts/ is a subdir)
|
||||
DATA_FILE = HERE / "data" / "launch-status.json"
|
||||
TZ_OFFSET = timedelta(hours=-4) # PYST (America/Asuncion)
|
||||
|
||||
# ── Day calculation ───────────────────────────────────────────────
|
||||
LAUNCH_START = date(2026, 6, 9)
|
||||
|
||||
def current_day() -> int:
|
||||
"""Return 1–14 based on days since launch start."""
|
||||
today = date.today()
|
||||
diff = (today - LAUNCH_START).days
|
||||
return max(1, min(14, diff + 1))
|
||||
|
||||
|
||||
# ── KPI probes ────────────────────────────────────────────────────
|
||||
|
||||
def probe_signups() -> int:
|
||||
"""Read signups from the payment webhook log or n8n status."""
|
||||
# TODO: wire up to n8n.derez.ai/webhook endpoint for count
|
||||
return 0
|
||||
|
||||
|
||||
def probe_visitors() -> int:
|
||||
"""Estimate landing page visitors via log analysis or a placeholder."""
|
||||
# TODO: integrate with analytics or server log parsing
|
||||
return 0
|
||||
|
||||
|
||||
def probe_emails() -> int:
|
||||
"""Email list signups."""
|
||||
return 0
|
||||
|
||||
|
||||
def probe_backlinks() -> int:
|
||||
"""Check for new referring domains."""
|
||||
return 0
|
||||
|
||||
|
||||
def probe_influencers() -> int:
|
||||
"""Count confirmed influencer partnerships."""
|
||||
return 0
|
||||
|
||||
|
||||
def probe_testimonials() -> int:
|
||||
"""Count collected F&F testimonials."""
|
||||
return 0
|
||||
|
||||
|
||||
def probe_impressions() -> int:
|
||||
"""Google Search Console impressions (last 7 days)."""
|
||||
return 0
|
||||
|
||||
|
||||
def probe_directory_listings() -> int:
|
||||
"""Count live directory listings (Product Hunt, BetaList, etc.)."""
|
||||
return 0
|
||||
|
||||
|
||||
# ── Main update ───────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
if not DATA_FILE.exists():
|
||||
print(f"ERROR: data file not found at {DATA_FILE}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
with open(DATA_FILE) as f:
|
||||
data = json.load(f)
|
||||
|
||||
day = current_day()
|
||||
|
||||
# Update KPIs with real probes
|
||||
kpi_map = {
|
||||
"signups": probe_signups,
|
||||
"visitors": probe_visitors,
|
||||
"emails": probe_emails,
|
||||
"backlinks": probe_backlinks,
|
||||
"influencers": probe_influencers,
|
||||
"testimonials": probe_testimonials,
|
||||
"impressions": probe_impressions,
|
||||
"directory": probe_directory_listings,
|
||||
}
|
||||
|
||||
for kpi in data.get("kpis", []):
|
||||
probe_fn = kpi_map.get(kpi["id"])
|
||||
if probe_fn:
|
||||
try:
|
||||
kpi["current"] = probe_fn()
|
||||
except Exception as e:
|
||||
print(f"WARN: probe failed for {kpi['id']}: {e}", file=sys.stderr)
|
||||
|
||||
# Update day number
|
||||
data["day"] = day
|
||||
|
||||
# Mark today's actions as "today" if they're still pending
|
||||
yesterday_actions = set()
|
||||
for action in data.get("actions", []):
|
||||
if action["day"] == day and action["status"] == "pending":
|
||||
action["status"] = "today"
|
||||
if action["status"] == "today":
|
||||
yesterday_actions.add(action["action"])
|
||||
|
||||
# Timestamp
|
||||
now = datetime.now(timezone.utc)
|
||||
data["updated"] = now.strftime("%Y-%m-%dT%H:%M:%S") + "-04:00"
|
||||
data["notes"] = f"Day {day} auto-update at {now.strftime('%H:%M')} UTC / {day}/14 complete."
|
||||
|
||||
with open(DATA_FILE, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
# Quiet success — no stdout so cron doesn't spam
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user