|
| 1 | +# @audius/migrate-tool |
| 2 | + |
| 3 | +A small web tool for moving an artist's tracks from an old Audius account to a |
| 4 | +new one — for cases where the artist has lost access to their original account |
| 5 | +(forgotten password, lost email) and has created a new account. |
| 6 | + |
| 7 | +Designed to be deployed to **migrate.audius.co** on Vercel with a Supabase |
| 8 | +database backing the request queue. |
| 9 | + |
| 10 | +## How it works |
| 11 | + |
| 12 | +1. The artist signs in with their new Audius account (OAuth via the Audius |
| 13 | + developer app). |
| 14 | +2. They enter the handle of their old account. The tool previews the tracks |
| 15 | + that would be migrated. |
| 16 | +3. They submit a migration request. The request is stored in Supabase with |
| 17 | + `status = 'pending'`. |
| 18 | +4. An Audius team member opens `/admin`, unlocks with the admin bearer token, |
| 19 | + and reviews the request. Identity verification (confirming the requester |
| 20 | + actually owns the old account) happens **out-of-band** via the usual |
| 21 | + support channel — the tool does not enforce it. |
| 22 | +5. On approval the backend pulls each old track's audio + artwork via the SDK |
| 23 | + and re-uploads it on the new account using the developer app's bearer |
| 24 | + token. Per-track results are written back to the DB and shown on the |
| 25 | + status page. |
| 26 | + |
| 27 | +## Limitations |
| 28 | + |
| 29 | +- **Original masters**: only tracks the artist marked as **downloadable** expose |
| 30 | + the original audio file via the public API. Other tracks migrate with the |
| 31 | + transcoded MP3 stream, which is a lossy re-encoding rather than a bit-for-bit |
| 32 | + copy. The track preview shows which of these applies per track. |
| 33 | +- **No identity verification in-tool**: anyone signed in can request migration |
| 34 | + of any handle. The approver is responsible for verifying the requester owns |
| 35 | + the old account before approving. Don't approve a request without |
| 36 | + confirming identity through a separate channel. |
| 37 | +- **Old account is not modified**: the tracks are re-created on the new |
| 38 | + account. The originals on the old account are untouched (the tool has no |
| 39 | + authority over the old account). |
| 40 | +- **No social-graph preservation**: plays, favorites, reposts, and comments |
| 41 | + on the old tracks do not carry over. |
| 42 | + |
| 43 | +## Deploy |
| 44 | + |
| 45 | +### 1. Supabase |
| 46 | + |
| 47 | +Create a project, then run the SQL in `supabase/migrations/0001_init.sql`. |
| 48 | + |
| 49 | +You'll need: |
| 50 | + |
| 51 | +- `SUPABASE_URL` — project URL |
| 52 | +- `SUPABASE_SERVICE_ROLE_KEY` — backend-only key (do not expose to the browser) |
| 53 | + |
| 54 | +### 2. Audius developer app |
| 55 | + |
| 56 | +Create a developer app at <https://audius.co/settings> → Developer Apps. You'll |
| 57 | +get an **API Key** and a **Bearer Token**. |
| 58 | + |
| 59 | +- `VITE_AUDIUS_API_KEY` — the API key (safe in the browser; baked into the build) |
| 60 | +- `AUDIUS_API_KEY` — same API key, for the backend |
| 61 | +- `AUDIUS_BEARER_TOKEN` — backend-only; grants the app permission to act on |
| 62 | + behalf of users who have authorized it via OAuth |
| 63 | + |
| 64 | +You'll also need to whitelist the deployment's OAuth redirect URI in the dev |
| 65 | +app's settings (e.g. `https://migrate.audius.co/`). |
| 66 | + |
| 67 | +### 3. Admin token |
| 68 | + |
| 69 | +- `ADMIN_BEARER_TOKEN` — pick a long random string. Share it only with team |
| 70 | + members authorized to approve migrations. |
| 71 | + |
| 72 | +### 4. Vercel |
| 73 | + |
| 74 | +```sh |
| 75 | +cd packages/migrate-tool |
| 76 | +npx vercel link |
| 77 | +npx vercel env add VITE_AUDIUS_API_KEY |
| 78 | +npx vercel env add AUDIUS_API_KEY |
| 79 | +npx vercel env add AUDIUS_BEARER_TOKEN |
| 80 | +npx vercel env add ADMIN_BEARER_TOKEN |
| 81 | +npx vercel env add SUPABASE_URL |
| 82 | +npx vercel env add SUPABASE_SERVICE_ROLE_KEY |
| 83 | +npx vercel --prod |
| 84 | +``` |
| 85 | + |
| 86 | +Then add `migrate.audius.co` as a domain in the Vercel project. |
| 87 | + |
| 88 | +## Local development |
| 89 | + |
| 90 | +```sh |
| 91 | +cp .env.example .env.local |
| 92 | +# Fill in the values, then: |
| 93 | +npm install |
| 94 | +npm run dev |
| 95 | +``` |
| 96 | + |
| 97 | +The Vite dev server runs at `http://localhost:5180`. To exercise the API |
| 98 | +functions locally, run them with `npx vercel dev` instead. |
| 99 | + |
| 100 | +## Approving a request |
| 101 | + |
| 102 | +1. Go to `https://migrate.audius.co/admin`. |
| 103 | +2. Paste the `ADMIN_BEARER_TOKEN` to unlock. |
| 104 | +3. Review the request — especially the old handle and the track list. |
| 105 | +4. **Verify the requester owns the old account through your usual support |
| 106 | + channel.** This is the only safeguard against migration abuse. |
| 107 | +5. Click **Approve & execute**. The backend runs the migration synchronously |
| 108 | + (Vercel function timeout is set to 5 minutes in `vercel.json`). |
| 109 | + |
| 110 | +## Files |
| 111 | + |
| 112 | +- `src/` — Vite + React SPA (home / status / admin pages) |
| 113 | +- `api/` — Vercel serverless functions |
| 114 | + - `api/requests/index.ts` — `POST /api/requests` (create) |
| 115 | + - `api/requests/[id].ts` — `GET /api/requests/:id` (status) |
| 116 | + - `api/admin/requests.ts` — `GET /api/admin/requests` (list, bearer-gated) |
| 117 | + - `api/admin/approve.ts` — `POST /api/admin/approve?id=…` (bearer-gated) |
| 118 | + - `api/admin/reject.ts` — `POST /api/admin/reject?id=…` (bearer-gated) |
| 119 | + - `api/_lib/migrate.ts` — migration worker |
| 120 | +- `supabase/migrations/0001_init.sql` — DB schema |
0 commit comments