> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myfundingmachine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Move existing owners to the free Slack workspace

> Reconcile existing owners, prepare private channels, and track each move without duplicate invitations or channels.

This staff workflow moves existing Funding Machine owners from
`fundingmachine.slack.com` to `myfundingmachine.slack.com`. Owners join the support
workspace as members and no longer need Slack Pro to communicate with Funding Machine.
Their business may still need a paid plan for its own workspace.

Migration uses a separate assignment registry. It does not restart onboarding,
change subscriptions, or send a new-customer payment welcome. Automatic assignment
requires the migration code to be deployed and its separate enable switch to be on;
preparing this workflow does not itself activate production automation.

## Choose eligible owners

Use the Operations account's **Retention** opportunity as the primary source of truth.
Check the contact, opportunity stage, status, tags, custom fields and saved Slack ID.
An open opportunity with a conflicting cancellation tag needs review.

Cross-check Stripe ownership subscriptions, including relevant older billing accounts.
A canceled subscription can have a current replacement. A current credit-pull or other
add-on subscription does not establish an active Funding Machine ownership account.
Hold unresolved billing discrepancies, paused or past-due accounts, uncertain identity
matches and **Transitioned to CEO Partner** records for a decision.

Match by exact account/contact identifiers, email and channel evidence. Names and
business names help locate candidates but do not authorize private-channel access.
Keep the Operations opportunity and the owner's product Location distinct.

## Check for an existing channel

Inspect the saved CRM channel ID, the new workspace and current membership before
creating anything. FM Bot can see only private channels it has joined. A successful
search returning no bot-visible match is not a complete duplicate check: inspect
staff-visible private channels as well and record the evidence and time checked.

If a matching channel already exists, verify its business and workspace, adopt its
ID and repair missing bot or staff membership within the approved scope. Do not
create a replacement just because FM Bot cannot see it. Multiple old channels for
one owner must resolve to one destination before preparation proceeds.

Channels follow the existing
[workspace naming and staff rules](/staff/slack-workspace):
`fm-{first-name}-{last-name}-{company-name}`, omitting the company when unavailable.
Names alone never establish that a channel belongs to an owner.

Company enrichment is best-effort: use the live CRM contact's nonblank company, or
fresh, explicitly reviewed company evidence from that exact contact or the linked
product Location's `business.name` / `name`. The CLI does not fetch the product
Location's business; `crm_location` evidence records an operator's scoped live
review. Never infer a business from an email domain or a fuzzy old channel match.
If evidence is missing, stale, scoped to another record, contradictory or malformed,
or the company would produce an invalid or overlong Slack name, preparation uses
`fm-{first-name}-{last-name}` and records a company-name review warning. Invalid
first or last names still hold preparation. Eligibility, identity, duplicate and
uncertain-write checks remain required.

An existing verified destination retains its live name. A naming mismatch is a
separate cleanup warning; it does not deny support or cause replacement creation.
Renaming needs explicit authorization for the exact channel and a live readback;
this CLI never renames. Reuse that channel's ID and ledger after an authorized rename.

## Prepare a batch before sending messages

Begin with a dry run of up to 25 approved owners. Keep held records separate and
review the proposed changes. For every included owner, finish all of these steps
before sending the batch's migration announcements:

1. Reserve the exact migration identity before any provider writes. This prevents
   onboarding from preparing the same owner concurrently. A saved creation-attempt
   marker prevents a lost local receipt from creating a second channel.
2. Verify or create the private destination channel using FM Bot and pin its ID to
   the reservation. A reviewed existing channel can retain its current name.
3. Confirm FM Bot and the configured internal support staff are members.
4. Save the new **Slack Channel ID** on the exact Operations Retention opportunity
   and confirm it by reading it back. Keep the previous ID in the migration receipt.
5. Enroll the approved owner email, product Location, opportunity and destination.
   Enrollment also updates the app's saved Location-to-channel mapping so support
   features use the new channel. Confirm that assignment is unpaused and the deployed
   worker is enabled; a preparing reservation is not an enrolled assignment.
6. Confirm the approved training link, workspace invitation and announcement text.

If preparation fails partway through, keep the receipts and finish or hold the
affected owner before outreach. Do not recreate channels that already succeeded.

Post the approved migration announcement in each owner's verified old channel and
mention the intended owner. Explain the benefit, link to the training and include
the current approved workspace invitation. Record the message link and timestamp.
The local preparation tool does not send these announcements.

## Automatic assignment and welcome

The worker uses the exact approved email to find an active human member of the new
workspace. Once that person joins the workspace, it adds them to the reserved private
channel. Events and recovery checks re-read current membership rather than relying
on event order. A different email needs staff identity review; matching a display
name is insufficient.

After channel membership is confirmed, FM Bot sends one welcome specifically for an
existing owner moving workspaces. An owner who already belongs to the channel uses
the same welcome path. The saved welcome receipt prevents a retry from intentionally
sending another welcome; an uncertain send needs delivery verification.

The worker does not create channels, change CRM opportunity fields, change billing
or archive old channels. Those remain explicit migration steps.

Connected migration assignments use the existing support-message handling with the
same verified private-channel and member checks. Preparing, waiting, paused or review
states do not grant automated support-message access. Resolve a welcome-delivery
review before treating the automated support flow as connected.
Verified staff replies can still stop an existing automated support response during
a pause, review or reconnect, provided its account and channel mapping remain valid.

## Confirm the move and archive

Check the correct private destination's live roster. An active human from the
owner's business can establish that the migration succeeded, even when a verified
teammate joins on the owner's behalf. Staff, bots and deactivated accounts do not
count. Staff may use several email addresses or workspace identities, so use the
verified staff roster and known aliases.

A teammate's presence does not authorize substituting their email for the primary
owner in the assignment registry. Resolve remaining eligibility and identity holds
before archiving. Review the old channel for a previous unarchive or another reason
to keep it open. Archive only the exact old channel covered by the approved move,
then read back its archived state.

## Track verified outcomes

Keep one row per owner/channel mapping, with these milestones separately recorded:

| Milestone | Evidence |
| - | - |
| Eligibility and identity | Retention opportunity/contact IDs, stage, status and billing cross-check |
| Destination prepared | Workspace and channel IDs, duplicate-check evidence, bot and staff membership |
| Company/name cleanup | Live destination name, proposed name, company evidence and naming warnings; separate rename approval/readback when applicable |
| CRM updated | Previous channel ID, new channel ID and successful readback |
| Assignment enrolled | Assignment ID, approved email, state and revision |
| Announcement sent | Old channel ID, message timestamp/link |
| Client joined | Active nonstaff member ID and live membership check |
| Welcome delivered | Destination message receipt or an explicit uncertain-delivery hold |
| Old channel archived | Old channel ID, archived-state readback and time |

A proposed next action is not a completed milestone. Historical checkboxes and
message-history exports do not establish current membership or archive state.
If the tracker update fails after a provider write, preserve the receipt and repair
the tracker before retrying the provider action.

## Manifest example

Keep the manifest outside the repository. This schema-valid example contains only
synthetic identities and intentionally old review timestamps. Replace every identity,
record the actual authorization and refresh the evidence before use; it is not a
live batch or approval to act.

```json theme={null}
{
  "batchId": "example-batch",
  "approvalRef": "Synthetic example; replace with the exact human authorization",
  "owners": [
    {
      "locationId": "example-product-location",
      "contactId": "example-operations-contact",
      "opportunityId": "example-retention-opportunity",
      "email": "owner@example.com",
      "previousChannelId": "CEXAMPLEOLD001",
      "expectedCrmChannelId": "",
      "companyReview": {
        "name": "Example Business",
        "source": "crm_location",
        "sourceId": "example-product-location",
        "checkedAt": "2026-01-01T12:00:00.000Z",
        "reviewedBy": "Example reviewer",
        "evidence": "Synthetic fixture only; replace with scoped live product Location business.name or name review"
      },
      "billing": {
        "status": "active",
        "subscriptionId": "sub_example",
        "checkedAt": "2026-01-01T12:00:00.000Z",
        "reviewedBy": "Example reviewer",
        "evidence": "Synthetic fixture only; replace with current ownership billing evidence"
      },
      "duplicateReview": {
        "checkedAt": "2026-01-01T12:00:00.000Z",
        "reviewedBy": "Example reviewer",
        "evidence": "Synthetic fixture only; no private-channel visibility has been verified"
      }
    }
  ]
}
```

`locationId` is the owner's product Location. `contactId` and `opportunityId` belong
to the Operations account. `previousChannelId` is the old workspace channel to retain
in the migration history. `expectedCrmChannelId` records the value actually read from
the opportunity: use `""` for a confirmed blank field, or the exact saved channel ID.
If omitted, it defaults to `previousChannelId`; do not use that default when the CRM
field is blank. The optional `channelId` adopts an already verified destination.

`billing.status` accepts `active` or `trialing`; a trial does not prove an invoice was
paid. Billing and staff-visible duplicate-review evidence must be refreshed within
24 hours. A missing duplicate review may appear in a dry-run report, but blocks live
preparation. Do not infer private-channel absence from FM Bot's search alone.

`companyReview` is optional enrichment, separate from access authorization. Its
`source` is `crm_contact` with `sourceId` equal to the exact `contactId`, or
`crm_location` with `sourceId` equal to the exact product `locationId`. Record the
verified company `name`, `checkedAt`, `reviewedBy` and descriptive `evidence`.
Reviews expire after 24 hours. A contact-source review must still match the live
contact company; a Location review conflicting with a nonblank live contact company
falls back with a warning for review. With no review, a nonblank live contact company
is used directly. Unusable review evidence falls back to the personal name even if
the contact has a company, so contradictions are not silently accepted.

Use 1–25 unique owners per manifest. Reuse the batch and receipts to resume the same
identities. Review timestamps can be refreshed; changes to the actual owner/channel
mapping require reconciliation with the saved receipts before continuing.
Adding, correcting or refreshing company evidence does not change the identity hash
or require a new ledger. Legacy manifests without company review remain usable.

## Tool controls and recovery

The repository's `scripts/onboarding/slack-migration.ts` provides `preflight`,
`prepare`, `enroll`, `status`, `pause`, `resume` and `reconnect`. It defaults to a dry
run. Batch commands use an external `--manifest`; applied preparation and enrollment
also require an external `--receipts` path. Live writes require both `--apply` and
`--prod`; omitting `--apply` keeps the command read-only. Inspect `--help` and the manifest
contract before running a batch. A dry run does not save an assignment or enable
background processing.

`SLACK_MIGRATION_ASSIGNMENT_ENABLED=true` is the separate worker switch and is off
by default. It also requires the existing support-workspace configuration to be
enabled. Deployment and production activation require approval for the named
environment; migration approval does not authorize a deployment. Existing onboarding
switches are not a substitute for the migration switch.

Read `status` before using the controls and pass the current assignment `--id`,
`--revision` and a `--reason`. **Pause** stops future assignment writes while keeping
existing channel access; a provider request already dispatched may finish. **Resume** revalidates the saved assignment before continuing. **Reconnect** is for
an explicitly approved restoration after a member was removed; it preserves the
welcome receipt. Do not use resume to override a removal or a changed identity.

On a timeout or unknown outcome, inspect the saved channel, opportunity, assignment
and message receipt before retrying. Reuse the original channel and stop on conflicting
mappings. Never remove a welcome receipt to force another send.

A preparing reservation keeps ownership even after a failed run. If channel creation
was attempted without a confirmed ID, recover that exact channel through Slack before
continuing; do not clear the server marker or switch receipt files to retry creation.
Pause/resume preserves preparation state. Reconnect applies only after enrollment.

Receipts pin `requestedName` before provider mutations and retain it on retry, even
when better company evidence appears later. `name` records the live Slack readback;
`namingWarnings` records enrichment and cleanup work. A legacy creation receipt's
saved name supplies the original intent when no `requestedName` exists. Preserve
creation-attempt markers, recovered channel IDs and welcome receipts. Unknown
creation still requires recovery of the original ID; editing company evidence or
switching ledgers cannot authorize a second creation. A new proposed company suffix
is a separate rename candidate, never a reason to recreate or abandon the ledger.

Keep manifests, receipts and customer exports outside the repository. Store credentials
in the approved environment, not command arguments, spreadsheets, screenshots or Git.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.