Skip to content

feat(scripts): import legacy deco admin teams into Studio - #5392

Open
viktormarinho wants to merge 1 commit into
mainfrom
viktormarinho/import-deco-teams
Open

feat(scripts): import legacy deco admin teams into Studio#5392
viktormarinho wants to merge 1 commit into
mainfrom
viktormarinho/import-deco-teams

Conversation

@viktormarinho

@viktormarinho viktormarinho commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What

One-shot, idempotent migration script (apps/api/scripts/import-deco-teams.ts) that replicates every legacy deco.cx admin team that owns at least one site (~434 teams, 742 sites today) into Studio: org, members, and one project agent per site.

How (per team)

  1. System user imports@deco.cx — inserted directly into user (no account row → not loggable). Owner of imported orgs and inviterId on invitations.
  2. Org — resolved in order: metadata.decoTeamId match (re-runs) → single org_sites owner → same slug + member-email overlap → created via Better Auth (auth.api.createOrganization, so seedOrgDb/reserved-slug/billing hooks all run). Every resolved org gets metadata.decoTeamId stamped — the persisted team↔org link backfill-org-sites.ts never had. New orgs are marked organization_billing.legacy = true (--no-legacy opts out).
  3. Members — silent 1-year invitation rows (no email blast; default invite expiry is 48h, too short for users who may show up months later). The pending invite suppresses the personal auto-org on first signup and reuses the existing accept screen. Legacy admin: true → role admin.
  4. Agents — one Virtual MCP per site with githubRepo, siteSlug, real productionUrl, preview-first layout. When DECO_GITHUB_MCP_TOKEN (deco machine account user-to-server grant) is set, it mints a refreshable repo grant via MINT_REPO_TOKEN and creates the repo-scoped child connection in the client org — the managed-assets model applied to GitHub: the client org only ever holds a token scoped to its own repo; renewal happens through the normal OAuth refresh path (github-repo-scope.ts), no broad credential ever lands in a client org. Repos whose owner has no installation visible to the machine account fall back to an unconnected githubRepo, completed by the first real user's GitHub OAuth.
  5. Emits team-org-mapping.json for the existing backfill-org-sites.ts --mapping= (org_sites claims + managed file configs).

Rollout

bun run scripts/import-deco-teams.ts --dry-run        # full report, zero writes
bun run scripts/import-deco-teams.ts --teams=<ids>    # pilot
bun run scripts/import-deco-teams.ts                  # full run; then backfill-org-sites

Safe to re-run: every step checks existing state first. Teams whose sites are already claimed by >1 Studio org (the two deco-internal teams) are skipped with a warning.

Testing

  • bunx tsc --noEmit, oxlint, bun run fmt clean.
  • Smoke: module boots and fails on the expected env guard without DECO_SUPABASE_URL.
  • Not yet run against prod — first real execution should be --dry-run with prod env.

Follow-up (out of scope)

Web affordance to finish the GitHub connection on an imported project that has githubRepo but no child connection (today that flow only exists inside the import dialog, which would create a duplicate project).


Summary by cubic

Adds a one-shot, idempotent script to import legacy deco.cx admin teams into Studio as orgs with members and one Virtual MCP agent per site, optionally provisioning repo‑scoped GitHub connections via a machine account. It also writes a team→org mapping JSON for the follow-up backfill.

  • New Features

    • Resolves or creates orgs and stamps organization.metadata.decoTeamId (owner is imports@deco.cx; new orgs can be marked legacy billing unless --no-legacy).
    • Creates silent, 1‑year invitations for team members (admin flag preserved) to avoid email blasts and suppress personal auto-orgs.
    • Adds one agent per site with githubRepo, siteSlug, production URL, and preview‑first layout.
    • With DECO_GITHUB_MCP_TOKEN, mints refreshable repo‑scoped tokens and creates a child GitHub connection; otherwise leaves githubRepo unconnected for later user OAuth.
    • Emits team-org-mapping.json for scripts/backfill-org-sites.ts --mapping=.... Safe to re-run; skips teams whose sites are owned by multiple orgs.
  • Migration

    • Dry run: bun run scripts/import-deco-teams.ts --dry-run
    • Pilot: bun run scripts/import-deco-teams.ts --teams=<ids>
    • Full: bun run scripts/import-deco-teams.ts [--no-legacy] → then bun run scripts/backfill-org-sites.ts --mapping=team-org-mapping.json

Written for commit bb9f2bc. Summary will update on new commits.

Review in cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant