#!/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()