Extract shared SignupFlowOverlay component. Static "Monthly Contribution" label on all three contribution inputs (was misleadingly dynamic). "Per Year"/"Per Month" toggle copy; Per Year default on accept-invite, Per Month default on join. Live billing-summary card on both signup flows. Welcome-heading on dashboard via ?welcome=1 for new signups. $0-member polish on account page (hide payment-history + Solidarity Fund prompts). State-aware contribution-change hint. Invite accept now creates Helcim customer and sets auth cookie server-side for both free and paid branches. Pre-registrant invite + /join signup flows manually verified against Cleo Nguyen preReg and $0-$50 variants. |
||
|---|---|---|
| .. | ||
| add-coop-values-series.js | ||
| add-cooperative-values-events.js | ||
| add-module-events-to-atlas.js | ||
| add-to-remote-db.js | ||
| check-events.js | ||
| check-old-event.js | ||
| check-series.js | ||
| cleanup-old-event.js | ||
| create-correct-series.js | ||
| debug-series.js | ||
| diagnose-query.js | ||
| fix-avatars.js | ||
| fix-series-id.js | ||
| helcim-plan-consolidation.js | ||
| list-all-series-events.js | ||
| merge-series.js | ||
| migrate-contribution-amount.cjs | ||
| migrate-ecology-to-board.cjs | ||
| migrate-event-slugs.js | ||
| mint-invite-link.cjs | ||
| README.md | ||
| reset-invite.cjs | ||
| seed-all.js | ||
| seed-events.js | ||
| seed-members.js | ||
| seed-series-events.js | ||
| seed-tags.js | ||
| seed-welcome-tester.cjs | ||
| setup-helcim-plans.js | ||
scripts/
One-off admin and migration scripts. None of these run in CI.
helcim-plan-consolidation.js
Consolidates Helcim payment plans from the legacy per-tier model (multiple plans at $15/$30/$50) to two unified plans (Monthly Membership at $15, Annual Membership at $150), and backfills Mongo members.
Required env
HELCIM_API_TOKEN=<token>
MONGODB_URI=<mongodb connection string>
Copy .env.example → .env if you haven't already.
Usage
# Dry-run (default) — no mutations, writes backup file
node scripts/helcim-plan-consolidation.js
# Execute all steps: delete subs, delete legacy plans, create new plans, update Mongo
node scripts/helcim-plan-consolidation.js --confirm
# Mongo cleanup only — skips all Helcim steps (use if Helcim steps already ran)
node scripts/helcim-plan-consolidation.js --mongo-only
What it does
- Backup — always written to
.migration-backup-<timestamp>.json, even in dry-run. Contains all Helcim subscriptions, payment plans, and Mongo members withhelcimSubscriptionId. - Delete subscriptions — deletes all Helcim subscriptions (
--confirmonly). - Delete legacy plans — deletes plan IDs
20162,21596,21597,21598, plus any plan whose name matches the legacy pattern (e.g. "Ghost Guild - Member ($15)"). - Create Monthly Membership — $15/month. Idempotent: skipped if a plan named "Monthly Membership" already exists.
- Create Annual Membership — $150/year. Same idempotency. Uses
billingPeriod: "yearly"(Helcim v2 convention); if Helcim returns 4xx, the script aborts and prints the full error so you can correct the field name. - Mongo cleanup —
updateManywithrunValidators: falseon all members withhelcimSubscriptionId: setscontributionTier: '0'andbillingCadence: 'monthly', unsetshelcimSubscriptionId. Does not changestatus.
At the end, prints new plan IDs formatted for copy-paste into .env.
Recovery
If something goes wrong mid-run, the backup JSON contains the pre-migration state. You can use the backup to:
- Identify which subscriptions existed before deletion.
- Identify which plan IDs to recreate manually in Helcim.
- Identify which members had
helcimSubscriptionIdbefore it was unset.
Backup files are gitignored (.migration-backup-*.json).
migrate-contribution-amount.cjs
One-time migration: converts Member.contributionTier (String enum) to
Member.contributionAmount (Number). Idempotent — only touches documents that
still have the legacy field.
Usage
node scripts/migrate-contribution-amount.cjs # dry-run
node scripts/migrate-contribution-amount.cjs --apply # write
What it does
Iterates members with contributionTier still set, parses each value as an integer
(valid: "0", "5", "15", "30", "50"), and writes the converted value to
contributionAmount. Unsets the old field. Skips any record that cannot be parsed.
Safe to re-run: only matches members where contributionTier still exists.