ADR: Miniapp Multi-Environment Deployment Model
Status: Accepted Date: 2026-01-29 Deciders: Founders, Engineering Team
Context
Current State
The Emerge miniapp is a Farcaster Mini App deployed to Vercel. Current deployment:
| Environment | Domain | Status |
|---|---|---|
| Production | emerge-mini-app.vercel.app | Working, but using Vercel subdomain |
| Staging | stg.q-miniapp.emerge.pizza | Deployed, but missing Farcaster credentials |
| Test | test.q-miniapp.emerge.pizza | Has credentials |
| Local | localhost:3338 | Uses EMBOT37 dev credentials |
Problems
- Production uses Vercel subdomain - Want custom domain for branding
- Staging can't function as miniapp - Missing Farcaster accountAssociation
- Local development friction - No ngrok setup for testing Farcaster features
- No clear environment separation - Farcaster agents (bots) not isolated per environment
Farcaster Constraints
Each domain requires its own signed accountAssociation because:
- The signature cryptographically includes the domain
- Domain in manifest must exactly match hosting FQDN
- Signatures cannot be reused across domains
Decision
1. Four-Environment Model
| Environment | Domain | Purpose | Deploy Trigger |
|---|---|---|---|
| Local | *.ngrok.pizza | Developer hot-reload testing | Manual |
| Staging | stg.q-miniapp.emerge.pizza | Pre-production testing | Push to staging |
| Test | test.q-miniapp.emerge.pizza | QA/automated testing | Push to test |
| Production | emerge.pizza (TBD) | Live users | Push to main |
2. Domain Strategy
Production: Add custom domain (e.g., app.emerge.pizza or emerge.pizza)
- Configure in Vercel dashboard
- Generate new Farcaster accountAssociation for custom domain
- Keep
emerge-mini-app.vercel.appas fallback/redirect
Staging/Test: Keep existing *.q-miniapp.emerge.pizza subdomains
- Already configured in DNS
- Generate Farcaster credentials for staging (currently missing)
Local Development: Ngrok with stable subdomain
- Use
emerge-mini-app-latest.ngrok.pizza(already in defaults) - Generate Farcaster credentials for ngrok domain
- Developers share the same ngrok credentials (or each dev gets own subdomain)
3. Farcaster Credentials Per Environment
Each environment needs its own set in secrets:
# Production (custom domain)
SECRET_FARCASTER_PROD_HEADER=...
SECRET_FARCASTER_PROD_PAYLOAD=...
SECRET_FARCASTER_PROD_SIGNATURE=...
# Staging
SECRET_FARCASTER_STG_HEADER=...
SECRET_FARCASTER_STG_PAYLOAD=...
SECRET_FARCASTER_STG_SIGNATURE=...
# Test
SECRET_FARCASTER_TEST_HEADER=...
SECRET_FARCASTER_TEST_PAYLOAD=...
SECRET_FARCASTER_TEST_SIGNATURE=...
# Local/Ngrok
SECRET_FARCASTER_NGROK_HEADER=...
SECRET_FARCASTER_NGROK_PAYLOAD=...
SECRET_FARCASTER_NGROK_SIGNATURE=...4. Farcaster Agent Isolation
Each environment should have its own Farcaster bot account:
| Environment | Bot Account | Purpose |
|---|---|---|
| Production | @emergebot | Real user interactions |
| Staging | @emergebot-stg | Pre-production testing |
| Test | @emergebot-test | QA automation |
| Local | @embot37 (existing) | Developer testing |
This prevents:
- Test casts appearing in production feeds
- Development activity polluting analytics
- Accidental production actions from staging
5. Vercel Project Configuration
Single Vercel project with environment-based deployments:
Vercel Project: emerge-miniapp
├── Production: main branch → custom domain
├── Preview: staging branch → stg.q-miniapp.emerge.pizza
└── Preview: test branch → test.q-miniapp.emerge.pizzaEnvironment variables set per Vercel environment (Production, Preview, Development).
Implementation
Phase 1: Fix Staging Credentials (Immediate)
- Generate Farcaster accountAssociation for
stg.q-miniapp.emerge.pizza- Use Warpcast mobile (Settings → Developer → Domains) or web tool
- Sign with the staging bot account
- Add to secrets:
SECRET_FARCASTER_STG_HEADER=... SECRET_FARCASTER_STG_PAYLOAD=... SECRET_FARCASTER_STG_SIGNATURE=... - Update
miniapp.envstaging section:[staging] FARCASTER_HEADER=${SECRET_FARCASTER_STG_HEADER} FARCASTER_PAYLOAD=${SECRET_FARCASTER_STG_PAYLOAD} FARCASTER_SIGNATURE=${SECRET_FARCASTER_STG_SIGNATURE}
Phase 2: Setup Ngrok for Local Development
- Get stable ngrok subdomain (ngrok paid plan or free
.ngrok.pizza) - Generate Farcaster accountAssociation for ngrok domain
- Add to secrets and update
[default]section - Document ngrok setup in README
Local dev workflow:
bash
# Terminal 1: Start ngrok
ngrok http 3338 --domain=emerge-mini-app-latest.ngrok.pizza
# Terminal 2: Start dev server
pnpm dev:miniappPhase 3: Add Production Custom Domain
- Choose domain (e.g.,
app.emerge.pizza) - Add domain in Vercel dashboard
- Configure DNS (CNAME or A record)
- Generate Farcaster accountAssociation for new domain
- Update production credentials in secrets
- Set up redirect from old Vercel domain
Phase 4: Create Environment-Specific Bot Accounts
- Create Farcaster accounts:
@emergebot-stgfor staging- Keep
@embot37for local dev
- Configure Neynar webhooks per environment
- Update bot credentials in each environment section
Updated miniapp.env Structure
env
NAMESPACE=MINIAPP
[default]
# Local development with ngrok
URL=https://emerge-mini-app-latest.ngrok.pizza
INGRESS=https://emerge-mini-app-latest.ngrok.pizza
FARCASTER_HEADER=${SECRET_FARCASTER_NGROK_HEADER}
FARCASTER_PAYLOAD=${SECRET_FARCASTER_NGROK_PAYLOAD}
FARCASTER_SIGNATURE=${SECRET_FARCASTER_NGROK_SIGNATURE}
BADGE=LOCAL
# ... other defaults
[staging]
URL=https://stg.q-miniapp.emerge.pizza
INGRESS=https://stg.q-miniapp.emerge.pizza
FARCASTER_HEADER=${SECRET_FARCASTER_STG_HEADER}
FARCASTER_PAYLOAD=${SECRET_FARCASTER_STG_PAYLOAD}
FARCASTER_SIGNATURE=${SECRET_FARCASTER_STG_SIGNATURE}
BADGE=STAGING
BYPASS_MAINTENANCE=true
[test]
URL=https://test.q-miniapp.emerge.pizza
INGRESS=https://test.q-miniapp.emerge.pizza
FARCASTER_HEADER=${SECRET_FARCASTER_TEST_HEADER}
FARCASTER_PAYLOAD=${SECRET_FARCASTER_TEST_PAYLOAD}
FARCASTER_SIGNATURE=${SECRET_FARCASTER_TEST_SIGNATURE}
BADGE=TEST
[production]
URL=https://app.emerge.pizza # New custom domain
INGRESS=https://app.emerge.pizza
FARCASTER_HEADER=${SECRET_FARCASTER_PROD_HEADER}
FARCASTER_PAYLOAD=${SECRET_FARCASTER_PROD_PAYLOAD}
FARCASTER_SIGNATURE=${SECRET_FARCASTER_PROD_SIGNATURE}
BADGE=
BYPASS_MAINTENANCE=falseConsequences
Positive
- Full miniapp functionality in all environments - Each has valid Farcaster credentials
- Safe testing - Bot activity isolated per environment
- Professional production domain - Custom domain for branding
- Local Farcaster testing - Ngrok enables testing miniapp features locally
- Clear separation - Each environment is fully independent
Negative
- Credential management overhead - 4 sets of Farcaster credentials to manage
- Multiple bot accounts - Need to create/maintain separate Farcaster accounts
- Ngrok dependency - Local dev requires ngrok for Farcaster testing
Neutral
- Vercel remains host - Good fit for Next.js, preview deploys work well
- DNS configuration required - One-time setup for custom domain
Alternatives Considered
1. Single Farcaster Account for All Environments
Rejected because:
- Credentials are domain-specific (can't reuse)
- Would pollute production with test activity
- No isolation for bot actions
2. Railway Instead of Vercel
Rejected because:
- Vercel optimized for Next.js
- Preview deploys work well
- No compelling reason to migrate
3. Skip Local Farcaster Testing
Rejected because:
- Can't test miniapp features without valid manifest
- Would slow development iteration
