{
  "version": 1,
  "states": [
    "found",
    "setup",
    "instrument",
    "blocked",
    "warming",
    "optional",
    "broken"
  ],
  "sources": [
    {
      "id": "gsc",
      "label": "Search Console export",
      "appliesTo": ["web", "marketing-site"],
      "priority": 1,
      "probe": [
        "verified domain property",
        "BigQuery dataset readable by pinned account",
        "searchdata_site_impression table",
        "export service-account IAM roles",
        "last data date"
      ],
      "missing": "Prepare IAM and the dataset, then enable Search Console bulk export.",
      "warming": "Dataset is readable, export IAM is present, and first tables are not older than 72 hours.",
      "broken": "Dataset is unreadable, IAM is absent, or an enabled export remains empty after 72 hours.",
      "reference": "references/website-onboarding.md"
    },
    {
      "id": "ga4",
      "label": "GA4 export",
      "appliesTo": ["web", "mobile", "native"],
      "priority": 2,
      "probe": [
        "production SDK or tag",
        "correct data stream",
        "analytics_<propertyId> dataset",
        "events_* tables",
        "production environment filter"
      ],
      "missing": "Instrument the product when needed, then enable Daily and Streaming BigQuery export.",
      "warming": "The BigQuery link is active and the first export tables have not landed.",
      "broken": "The configured dataset is unreadable or the stream/filter excludes production events.",
      "reference": "references/website-onboarding.md"
    },
    {
      "id": "vercel",
      "label": "Vercel Analytics",
      "appliesTo": ["web"],
      "priority": 3,
      "probe": [
        "Vercel project binding",
        "@vercel/analytics framework component",
        "production loader request"
      ],
      "missing": "Enable Web Analytics and mount the official framework component when the app is hosted on Vercel.",
      "warming": "The loader is live and Vercel has not displayed its first visit.",
      "broken": "The project says enabled but the production loader never runs.",
      "reference": "references/website-onboarding.md"
    },
    {
      "id": "app-store-connect",
      "label": "App Store Connect",
      "appliesTo": ["mobile", "native"],
      "priority": 4,
      "probe": [
        "key id",
        "issuer id",
        "readable .p8 path",
        "vendor number",
        "analytics report request"
      ],
      "missing": "Offer App Store Connect after the dashboard is live unless store metrics are required.",
      "warming": "The key works and Apple is preparing its first analytics reports.",
      "broken": "The scheduled process cannot read the key or mint an accepted JWT.",
      "reference": "references/app-onboarding.md"
    },
    {
      "id": "revenuecat",
      "label": "RevenueCat",
      "appliesTo": ["mobile", "native"],
      "priority": 5,
      "probe": [
        "secret key in scheduler-readable env",
        "project discovery",
        "product and app scope"
      ],
      "missing": "Offer RevenueCat when subscriptions or in-app purchases use it.",
      "warming": "Not applicable; a valid key is immediately readable.",
      "broken": "The key is configured but the scheduled process cannot list its project.",
      "reference": "references/app-onboarding.md"
    },
    {
      "id": "dataforseo",
      "label": "DataForSEO",
      "appliesTo": ["web", "marketing-site"],
      "priority": 6,
      "probe": [
        "key in scheduler-readable env",
        "balance",
        "target market and language"
      ],
      "missing": "Optional: explain the first-run cost before rank and backlink pulls.",
      "warming": "Not applicable; a valid key is immediately readable.",
      "broken": "The key is configured but rejected or invisible to the scheduler.",
      "reference": "references/sources.md"
    },
    {
      "id": "targets",
      "label": "Tracked keywords",
      "appliesTo": ["web", "marketing-site"],
      "priority": 7,
      "probe": [
        "UTF-8 CSV",
        "unique non-empty keywords",
        "maximum 150 rows",
        "target page mapping"
      ],
      "missing": "Optional: research competitors, batch-check demand, and curate targets.",
      "warming": "Not applicable.",
      "broken": "The CSV is malformed, empty, duplicated, or over 150 rows.",
      "reference": "references/website-onboarding.md"
    },
    {
      "id": "scheduler",
      "label": "Scheduled refresh",
      "appliesTo": ["web", "mobile", "native"],
      "priority": 8,
      "probe": [
        "scheduler loaded",
        "doctor --as-cron",
        "log path writable",
        "provider credentials visible without shell exports"
      ],
      "missing": "Install the platform scheduler after the first refresh.",
      "warming": "Not applicable.",
      "broken": "Interactive checks pass but scheduler-mode checks fail.",
      "reference": "references/sources.md"
    }
  ]
}
