{
  "for_llm": "This page documents ONE part of LeadLift's coded OS plus the Make scenarios it calls: a Whop payment -> client row -> 17 onboarding steps -> three legs (Slack, Drive via Make, Skool + welcome email). To change it, open the repo in code.repo and read the stage file and code.files. change_policy: green = the app can write it; amber = a named business rule with a test (change rule + test together, merge through the gate); red = a contract other parts call (routes, tables, events, step names), a setting or secret, or a Make scenario. Facts are as of main e0a8709 (12 Oct 2026).",
  "system": "LeadLift Onboarding",
  "unit": {
    "index": 1,
    "of": 3,
    "node": "Payment to onboarding started"
  },
  "platform": "code (Modal) + make.com",
  "code": {
    "repo": "https://github.com/Icarus-Growth/leadlift-os",
    "ref": "main e0a8709",
    "stage": "os/process/ll-onboarding-flow.md",
    "boxes": [
      "2",
      "3",
      "7",
      "8",
      "9",
      "10",
      "11",
      "13",
      "14",
      "15",
      "24",
      "25"
    ],
    "files": [
      "deploy/handlers/whop.py",
      "os/api/whop.py",
      "automations/jobs/onboarding_contract/whop_intake.py",
      "os/api/onboarding.py (STEPS, start, record_leg, report)",
      "os/api/onboarding_legs.py (slack_leg, slack_steps, drive_leg, after_drive, send_fidel_welcome, give_drive_access, drive_access_grants, skool_email_leg, welcome_email, make_form_link)",
      "shared/email_template.py",
      "deploy/app.py (run_onboarding_leg)",
      "os/db/migration-onboarding-dedupe-and-stamps.sql",
      "os/db/migration-2026-10-11-media-buyer.sql (clients_default_media_buyer)",
      "tests/onboarding/"
    ]
  },
  "make_scenarios": [
    {
      "id": 6581813,
      "team": 438268,
      "zone": "us2",
      "name": "STEP 1: Client Paid >> Create Drive Folder",
      "modules": "webhook, create client folder + 5 subfolders, share Raw Footage anyone-with-link writer, report to /onboarding/leg, error routes to /ops/sentry",
      "notes": "automations/make/onboarding-drive/README.md"
    },
    {
      "id": 6582021,
      "team": 438268,
      "zone": "us2",
      "name": "STEP 1B: Client Channel Created >> Fidel Welcome Message",
      "modules": "webhook, Slack post as Fidel's user connection, report to /onboarding/leg",
      "notes": "automations/make/fidel-welcome/README.md"
    },
    {
      "id": 6585401,
      "team": 438268,
      "zone": "us2",
      "name": "STEP 1C: Drive Folder Made >> Give Edit Access",
      "modules": "webhook, iterator over grants, Drive permissions create, patch role when Drive kept another, errors to sentry_url",
      "notes": "automations/make/drive-access/README.md"
    }
  ],
  "trigger": {
    "type": "Whop webhook POST /whop/payment (Standard Webhooks signature, WHOP_WEBHOOK_SECRET)",
    "filter": "event type payment.succeeded AND 'onboarding' (case-insensitive substring) in product.title or plan.title",
    "also": "a test payment carrying the _e2e marker"
  },
  "reads": [
    {
      "table": "clients",
      "why": "the cascade: whop_payment_id, whop_membership_id, whop_user_id, then exactly one email/form_email match"
    },
    {
      "table": "team",
      "why": "Active members' slack_user_id (channel invites) and email (Drive grants)"
    }
  ],
  "writes": [
    {
      "table": "clients",
      "why": "insert at '0 - Paid' / status Onboarding, or fill empty fields; onboarding_thread_ts, slack_channel_id, google_drive_folder_id, drive_*_folder_id, skool_invite_sent"
    },
    {
      "table": "onboarding_steps",
      "why": "17 rows per client, keyed (client_id, step_name); each leg stamps complete or Blocked"
    },
    {
      "volume": "leadlift-webhook-inbox/whop/",
      "why": "every raw Whop event"
    }
  ],
  "notifies": [
    {
      "slack": "#payments (SLACK_CHANNEL_PAYMENTS)"
    },
    {
      "slack": "#onboarding launch message + per-client thread (SLACK_CHANNEL_ONBOARDING)"
    },
    {
      "slack": "new private client channel (clients.slack_channel_id)"
    },
    {
      "slack": "#sentry when Make cannot report back"
    },
    {
      "email": "welcome email through Resend, subject 'Welcome to LeadLift! (Onboarding)'"
    }
  ],
  "schedules": [],
  "edges": {
    "upstream": [
      {
        "node": "Prerequisites: Whop products and Make",
        "unit": 3,
        "via": "the product-name filter and the three Make scenarios"
      }
    ],
    "downstream": [
      {
        "node": "Onboarding form to onboarded",
        "unit": 2,
        "via": "welcome email carries the client's own form link (POST /api/onboarding/link on the form's server)"
      },
      {
        "node": "Contract (reserved slot 04, pending)",
        "unit": 4,
        "via": "runs alongside, by hand today; gates nothing"
      }
    ]
  },
  "capabilities": [
    "Verifies Whop's signature, keeps every raw event, posts every successful payment to #payments",
    "Starts onboarding only for a payment.succeeded whose product or plan title contains 'onboarding' (any case)",
    "Finds or creates the client (payment, membership, Whop user, exactly one email match, else new); the same payment twice never makes two rows (unique whop_payment_id)",
    "Flags a possible duplicate for a new client (phone, name, fuzzy; never AI; never merges)",
    "Lays out 17 steps, posts the #onboarding launch message, and spawns the Slack and Skool+email legs on Modal; the Slack leg then fires the Drive leg",
    "Slack leg: private channel, invites every Active team row with a slack_user_id plus ONBOARDING_ALERT_SLACK_ID and Viktor, sets the topic, sends a Slack Connect invite to the client's email",
    "Drive (Make 6581813): client folder in 'Clients' + Raw Footage, Edited, Lead Sheet, Contract, Brief; Raw Footage anyone-with-link can edit",
    "After the folder: Raw Footage bookmark in the channel, Fidel's welcome via Make 6582021 (once per client), grants via Make 6585401",
    "Skool add-member + welcome email with three buttons (own form link, booking link, Skool)",
    "Every step writes one \u2713/\u2717 line in the client's #onboarding thread; a \u2717 line tags ONBOARDING_ALERT_SLACK_ID"
  ],
  "boundaries": [
    "Does not draft or send the contract (boxes 4-6, reserved slot 04, by hand)",
    "Does not handle failed or past-due payments: box 25 is not built; a non-succeeded event changes nothing (paid_status is set by hand)",
    "A client at '100 - Onboarded' or already launched never launches again; a renewal (matched by membership) never launches",
    "A new client is never matched by a guess; a possible duplicate is only flagged",
    "No real payment has run through as of 12 Oct; none of the real products' titles contains 'onboarding'"
  ],
  "change_policy": {
    "green": [
      "clients: first_name, last_name, email, phone, paid_status, contract_value, contract_start_date, management_window_months, management_window_ends, assigned_media_buyer_id, assigned_client_manager_id (client page)",
      "team: status, slack_user_id, email (Team page)"
    ],
    "amber": [
      "ONBOARDING_WORD = 'onboarding' (Sheni, 2026-10-10; tests/onboarding/test_whop_intake.py)",
      "FIRST_PAYMENT = {one_time, subscription_create} (Sheni, 2026-10-10)",
      "WINDOW_MONTHS = '3' (Sheni, 2026-10-10)",
      "WELCOME_SUBJECT and welcome_email / fidel_welcome_text wording (Sheni, 2026-10-10; tests hold them)"
    ],
    "red": [
      "route.whop_payment_webhook POST /whop/payment",
      "WHOP_WEBHOOK_SECRET",
      "MAKE_HOOK_DRIVE_FOLDER / MAKE_HOOK_FIDEL_WELCOME / MAKE_HOOK_DRIVE_ACCESS and the three scenarios",
      "ONBOARDING_LEG_SECRET (Modal, the form's Cloudflare worker, Make)",
      "route.onboarding_leg POST /onboarding/leg",
      "tables clients / onboarding_steps / team and the onboarding_step_name enum",
      "ONBOARDING_ALERT_SLACK_ID (defaults to Sheni's Slack user; tagged on every \u2717 line and invited to every new client channel)",
      "ONBOARDING_DUPLICATE_SLACK_ID (set to Sheni's Slack user in .env as of 12 Oct)"
    ]
  },
  "known_issues": [
    "19 of the 50 imported real clients have no email: a payment from one of them makes a duplicate client and a full second onboarding",
    "ONBOARDING_ALERT_SLACK_ID and ONBOARDING_DUPLICATE_SLACK_ID point at Icarus Growth (Sheni); must move to a LeadLift person at handover",
    "Box 25 (failed / past-due payment) is described in the stage file but not built",
    "Box 8 in the stage file says a fixed list of four people; the code invites every Active team row with a slack_user_id (Sterlin has none today)",
    "Box 14 in the stage file says Modal walks and copies a template tree; as built, Make 6581813 creates 6 fresh folders",
    "ONBOARDING_LEG_SECRET shows in Make's run log for 30 days (Make receives it in the webhook body)",
    "Make's Google Drive connection expires 11 Apr 2027"
  ],
  "recovery": {
    "git": "every change is a commit on main, merged through the gate",
    "rollback": "modal app rollback leadlift-os",
    "blueprint_backup": [
      "backups/bp_6581813.json",
      "backups/bp_6582021.json",
      "backups/bp_6585401.json"
    ]
  }
}