# B20X Registry Storage

This page explains the production storage modes used by the B20X launch collection.

## Current Public Mode

The deployed launch page can already show tokens without manual CA upload:

```text
configured creator wallet
-> public BSC launch snapshot
-> token CA + image + metrics
-> B20X launch collection
```

This is the active mode when `/api/registry/health` reports:

```json
{
  "storage_mode": "memory",
  "persistent": false,
  "display_mode": "public-feed+signed-preview"
}
```

In this mode, public launch discovery is active. Wallet signatures can still create a local browser preview, but final signed registry writes are not persisted across Vercel serverless instances.

The deployment also carries a read-only pinned launch snapshot at `data/pinned-launches.json`. It is not the main write path; it is a resilience layer for already verified CAs so the launch page can still render known B20X launches if the external discovery source is slow or unavailable.

To refresh that pinned snapshot from the live registry/API without hand-editing JSON:

```bash
cd outputs/b20x-site
npm run pin:launches -- --creator-wallet 0xCreatorWallet --dry-run
npm run pin:launches -- --creator-wallet 0xCreatorWallet
```

For normal operation, put all creator wallets in `B20X_DEFAULT_CREATOR_WALLETS`, then run:

```bash
cd outputs/b20x-site
npm run pin:default-wallets -- --dry-run
npm run pin:default-wallets
```

You can also pass several wallets directly:

```bash
npm run pin:launches -- --creator-wallets 0xCreatorA,0xCreatorB
```

You can also pin a single known CA:

```bash
npm run pin:launches -- --ca 0xTokenCA
```

If you deployed from the local SDK and already have `outputs/b20x-sdk/.env.deployer`, refresh by deriving the public creator wallet from that local key:

```bash
cd outputs/b20x-site
npm run pin:from-deployer -- --sdk-env ../b20x-sdk/.env.deployer --dry-run
npm run pin:from-deployer -- --sdk-env ../b20x-sdk/.env.deployer
```

`pin:from-deployer` prints only the public creator wallet and never prints the private key.

The script merges by CA and writes only the compact, public fields needed for the deployed fallback.
`/api/registry/health` and `npm run doctor:registry` both report the pinned snapshot status and count so operators can see whether the deployed fallback is ready.

## Operator Status Check

Run the operator status check when you want one screen for production visibility, pinned snapshot state, canary CA lookup, GitHub Actions refresh status, and optional Vercel deploy readiness:

```bash
cd outputs/b20x-site
npm run ops:status
```

Useful variants:

```bash
npm run ops:status -- --ca 0xTokenCA
npm run ops:status -- --json
npm run ops:status -- --strict
```

`--strict` exits non-zero when any warning remains. In the current public mode, the most likely warning is a missing `VERCEL_TOKEN` repository secret: snapshot refresh still works, but refreshed snapshots will not auto-deploy until that secret is configured.

## Automated Snapshot Refresh

The repository includes `.github/workflows/refresh-pinned-launches.yml` for a lightweight automatic refresh loop.

It runs on a schedule and can also be triggered manually from GitHub Actions. The workflow:

```text
creator wallets / CA input
-> live B20X registry API
-> outputs/b20x-site/data/pinned-launches.json
-> commit only when the snapshot changes
```

Recommended GitHub repository variable:

```text
B20X_DEFAULT_CREATOR_WALLETS=0xCreatorWallet,0xAnotherWallet
```

Optional GitHub repository variable:

```text
B20X_REGISTRY_URL=https://site-registry-core-0624.vercel.app
```

Manual workflow inputs:

```text
creator_wallets=0xCreatorA,0xCreatorB
ca=0xTokenA,0xTokenB
replace=true
```

Leave `creator_wallets` and `ca` empty to use `B20X_DEFAULT_CREATOR_WALLETS`.
The workflow uses the repository `GITHUB_TOKEN` with `contents: write`; no personal GitHub token is needed for this pinned-snapshot path.

The workflow can also deploy the refreshed snapshot to Vercel after it commits a change. Set these GitHub repository variables:

```text
VERCEL_ORG_ID=team_X57ocgS0mjV7kbvupBAMdweU
VERCEL_PROJECT_ID=prj_L3fORVuWs9hH68LgEEc1fj1CwjLT
```

Then set this GitHub repository secret:

```text
VERCEL_TOKEN=<Vercel access token>
```

Local setup helper:

```bash
cd outputs/b20x-site
npm run preflight:vercel-ci -- --dry-run
VERCEL_TOKEN=vercel_xxx npm run preflight:vercel-ci
VERCEL_TOKEN=vercel_xxx npm run configure:vercel-ci
```

`configure:vercel-ci` validates the token against the linked Vercel project, sets `VERCEL_ORG_ID` and `VERCEL_PROJECT_ID` as repository variables, and writes `VERCEL_TOKEN` as a GitHub repository secret through stdin so the token is not passed as a command argument.

If `VERCEL_TOKEN` is missing, the workflow still refreshes and commits the pinned snapshot, but skips deployment with a clear log message. If you keep the project as CLI-only deployment, run a production deploy after a snapshot commit:

```bash
cd outputs/b20x-site
npx vercel deploy --prod --yes
```

## Persistent Signed Registry

Persistent mode stores signed B20X launch records in the private GitHub repository through the GitHub Contents API.

It does not require making the repository public. Use a fine-grained GitHub token with only:

```text
Repository: huhuhu69420/site-registry-core-0624
Permission: Contents read/write
Scope: selected repository only
```

Do not use a broad account token unless you explicitly accept that wider repository access risk.
The setup scripts enforce this by default: `configure:registry-env`, `preflight:registry-github`, and `doctor:registry` treat `github_pat_...` as the expected token format and reject broad `ghp_` / `gho_` style tokens unless you explicitly opt in with `B20X_ALLOW_BROAD_GITHUB_TOKEN=true` or `--allow-broad-token`.

Required Vercel environment variables:

```text
B20X_REGISTRY_GITHUB_TOKEN=github_pat_...
B20X_REGISTRY_GITHUB_REPO=huhuhu69420/site-registry-core-0624
B20X_REGISTRY_GITHUB_BRANCH=main
B20X_REGISTRY_GITHUB_PATH=outputs/b20x-site/data/registry.json
B20X_PUBLIC_SNAPSHOT_ENABLED=true
B20X_PUBLIC_SNAPSHOT_URL=https://four.meme/en
B20X_PUBLIC_SNAPSHOT_MAX_RECORDS=600
B20X_PINNED_SNAPSHOT_ENABLED=true
B20X_PINNED_SNAPSHOT_PATH=data/pinned-launches.json
```

Optional variables:

```text
B20X_DEFAULT_CREATOR_WALLETS=0xCreatorWallet,0xAnotherWallet
BSC_RPC_URL=https://...
BSCSCAN_API_KEY=...
B20X_LAUNCH_FACTORY_ADDRESSES=0xFactoryA,0xFactoryB
B20X_WALLET_SYNC_MAX_AGE_MS=600000
```

## Local Preflight

Create `outputs/b20x-site/.env.local` with the variables above, then run:

```bash
cd outputs/b20x-site
npm run preflight:registry-github -- --write-probe
```

Expected result:

```text
token: fine-grained
read:  ok
write: ok
```

## Configure Vercel

After the preflight passes:

```bash
cd outputs/b20x-site
npm run configure:registry-env -- --dry-run
npm run configure:registry-env
npx vercel deploy --prod --yes
```

Then verify:

```bash
curl -s https://site-registry-core-0624.vercel.app/api/registry/health
```

Healthy persistent mode should show:

```json
{
  "storage_mode": "github",
  "persistent": true,
  "ready": true,
  "write_mode": "persistent"
}
```

## User Flow After Persistent Mode

```text
creator deploys through the supported BSC route
-> creator opens /launches.html
-> creator connects the same wallet
-> creator signs B20X Wallet Sync locally
-> server indexes matching BSC launch records
-> verified CA is written to data/registry.json
-> launch collection displays it for every visitor
```

The server never receives the BSC private key. It receives only a wallet signature, public CA data, and public launch evidence.
