Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions .github/workflows/deploy-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,25 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: NeuroWealth-Frontend

steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4

- uses: actions/setup-node@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: NeuroWealth-Frontend/package-lock.json
node-version: "20"
cache: "yarn"

- name: Install dependencies
run: npm ci --legacy-peer-deps --omit=optional
run: yarn install --frozen-lockfile

- name: Validate environment variables
run: npm run validate:env
run: yarn validate:env
env:
NEXT_PUBLIC_APP_ENV: ${{ secrets.PROD_APP_ENV }}
NODE_ENV: production
NEXT_PUBLIC_APP_ENV: production
NEXT_PUBLIC_APP_URL: ${{ secrets.PROD_APP_URL }}
WHATSAPP_APP_SECRET: ${{ secrets.PROD_WHATSAPP_APP_SECRET }}
WHATSAPP_VERIFY_TOKEN: ${{ secrets.PROD_WHATSAPP_VERIFY_TOKEN }}
Expand All @@ -43,14 +42,23 @@ jobs:
STELLAR_HORIZON_URL: https://horizon.stellar.org
WALLET_ENCRYPTION_KEY: ${{ secrets.PROD_WALLET_ENCRYPTION_KEY }}

- name: Typecheck
run: yarn typecheck

- name: Lint
run: yarn lint

- name: Build
run: npm run build
run: yarn build
env:
NODE_ENV: production
NEXT_PUBLIC_APP_ENV: production
NEXT_PUBLIC_APP_URL: ${{ secrets.PROD_APP_URL }}
STELLAR_NETWORK: mainnet
STELLAR_HORIZON_URL: https://horizon.stellar.org

- name: Deploy to Vercel (Production)
run: npx vercel --prod --token=${{ secrets.VERCEL_TOKEN }} --yes
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
34 changes: 21 additions & 13 deletions .github/workflows/deploy-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,25 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: NeuroWealth-Frontend

steps:
- uses: actions/checkout@v4
- name: Checkout repository
uses: actions/checkout@v4

- uses: actions/setup-node@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: Neurowealth-Frontend/package-lock.json
node-version: "20"
cache: "yarn"

- name: Install dependencies
run: npm ci --legacy-peer-deps --omit=optional
run: yarn install --frozen-lockfile

- name: Validate environment variables
run: npm run validate:env
run: yarn validate:env
env:
NEXT_PUBLIC_APP_ENV: ${{ secrets.STAGING_APP_ENV }}
NODE_ENV: production
NEXT_PUBLIC_APP_ENV: staging
NEXT_PUBLIC_APP_URL: ${{ secrets.STAGING_APP_URL }}
WHATSAPP_APP_SECRET: ${{ secrets.STAGING_WHATSAPP_APP_SECRET }}
WHATSAPP_VERIFY_TOKEN: ${{ secrets.STAGING_WHATSAPP_VERIFY_TOKEN }}
Expand All @@ -44,14 +43,23 @@ jobs:
STELLAR_HORIZON_URL: https://horizon-testnet.stellar.org
WALLET_ENCRYPTION_KEY: ${{ secrets.STAGING_WALLET_ENCRYPTION_KEY }}

- name: Typecheck
run: yarn typecheck

- name: Lint
run: yarn lint

- name: Build
run: npm run build
run: yarn build
env:
NODE_ENV: production
NEXT_PUBLIC_APP_ENV: staging
NEXT_PUBLIC_APP_URL: ${{ secrets.STAGING_APP_URL }}
STELLAR_NETWORK: testnet
STELLAR_HORIZON_URL: https://horizon-testnet.stellar.org

- name: Deploy to Vercel (Staging)
run: npx vercel --token=${{ secrets.VERCEL_TOKEN }} --yes
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
46 changes: 46 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# syntax=docker/dockerfile:1

# ── Stage 1: install dependencies ─────────────────────────────────────────────
FROM node:20-alpine AS deps
WORKDIR /app

COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile --production=false

# ── Stage 2: build ────────────────────────────────────────────────────────────
FROM node:20-alpine AS builder
WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules
COPY . .

ARG NEXT_PUBLIC_APP_ENV=production
ARG NEXT_PUBLIC_APP_URL
ENV NEXT_PUBLIC_APP_ENV=${NEXT_PUBLIC_APP_ENV}
ENV NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL}
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN yarn build

# ── Stage 3: production runtime ───────────────────────────────────────────────
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs

COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["node", "server.js"]
155 changes: 128 additions & 27 deletions docs/deployment.md
Original file line number Diff line number Diff line change
@@ -1,62 +1,163 @@
# Deployment Guide for NeuroWealth Frontend
# Deployment Guide NeuroWealth Frontend

## Environments

| Environment | Branch | Stellar Network | URL |
|-------------|---------|-----------------|-----|
| Staging | `dev` | Testnet | https://staging.neurowealth.com |
| Production | `main` | **Mainnet** | https://neurowealth.com |
| Environment | Branch | Stellar Network | URL |
|-------------|-----------|-----------------|---------------------------------------|
| Staging | `dev` | Testnet | https://staging.neurowealth.com |
| Production | `main` | **Mainnet** | https://neurowealth.com |

> ⚠️ Production uses Stellar Mainnet and real USDC. Never deploy untested code to `main`.

## Pre-Release Checklist
---

## Environment Variables

Copy `.env.example` and fill in real values before deploying:

- [ ] PR reviewed and approved by at least 1 maintainer
- [ ] All CI checks passing (env validation + build)
- [ ] Staging deploy verified — test deposit, balance check, and withdrawal flows via WhatsApp
- [ ] No console errors on staging
- [ ] `STELLAR_NETWORK` confirmed as `mainnet` in production secrets
- [ ] `WALLET_ENCRYPTION_KEY` is unique and securely stored in a password manager
- [ ] Database migrations run on production DB if schema changed:
```bash
psql -d neurowealth -f backend/migrations/001_create_users_table.sql
psql -d neurowealth -f backend/migrations/002_create_deposits_table.sql
cp .env.example .env.local # local dev
```
- [ ] CHANGELOG updated

Required secrets stored in GitHub → Settings → Secrets and variables → Actions:

| Secret name (staging prefix `STAGING_`, production prefix `PROD_`) | Description |
|---|---|
| `APP_URL` | Public origin, e.g. `https://staging.neurowealth.com` |
| `WHATSAPP_APP_SECRET` | Meta WhatsApp Cloud API secret |
| `WHATSAPP_VERIFY_TOKEN` | Webhook verification token |
| `WHATSAPP_ACCESS_TOKEN` | API access token |
| `WHATSAPP_PHONE_NUMBER_ID` | Linked phone number ID |
| `WHATSAPP_WABA_ID` | WhatsApp Business Account ID |
| `DB_HOST` / `DB_PORT` / `DB_NAME` / `DB_USER` / `DB_PASSWORD` | PostgreSQL connection |
| `WALLET_ENCRYPTION_KEY` | 32-byte hex key (generate: `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"`) |
| `VERCEL_TOKEN` | Vercel personal access token |
| `VERCEL_ORG_ID` | Vercel org/team ID |
| `VERCEL_PROJECT_ID` | Vercel project ID |

---

## CI Pipeline (all PRs and main/dev pushes)

Workflow: `.github/workflows/frontend-ci.yml`

Steps run on every PR and push to `main`/`master`:

1. `yarn install` — install locked dependencies
2. `yarn typecheck` — TypeScript strict check
3. `yarn test` — unit tests
4. `yarn lint` — ESLint
5. `yarn build` — production build

---

## Deploying to Staging

Push to or merge a PR into `dev`. GitHub Actions runs automatically.
Monitor: **Actions → Deploy to Staging**
Push to or merge a PR into `dev` (or `staging`).
Workflow `.github/workflows/deploy-staging.yml` triggers automatically.

Steps:
1. `yarn install --frozen-lockfile`
2. `yarn validate:env` — validates all required env vars are present
3. `yarn typecheck` + `yarn lint`
4. `yarn build` with `NEXT_PUBLIC_APP_ENV=staging`
5. `npx vercel --yes` — deploy preview to Vercel

Monitor: **GitHub → Actions → Deploy to Staging**

### Manual staging deploy

```bash
NEXT_PUBLIC_APP_ENV=staging NEXT_PUBLIC_APP_URL=https://staging.neurowealth.com yarn build
npx vercel --token=$VERCEL_TOKEN --yes
```

---

## Deploying to Production

Merge `dev` → `main` via a Pull Request. GitHub Actions runs automatically.
Monitor: **Actions → Deploy to Production**
Merge `dev` → `main` via a reviewed Pull Request.
Workflow `.github/workflows/deploy-production.yml` triggers automatically.

Steps:
1. `yarn install --frozen-lockfile`
2. `yarn validate:env` — validates all required env vars are present
3. `yarn typecheck` + `yarn lint`
4. `yarn build` with `NEXT_PUBLIC_APP_ENV=production`
5. `npx vercel --prod --yes` — promote to Vercel production alias

Monitor: **GitHub → Actions → Deploy to Production**

---

## Pre-Release Checklist

- [ ] PR reviewed and approved by at least 1 maintainer
- [ ] All CI checks green (typecheck, tests, lint, build)
- [ ] Staging deploy verified — test deposit, balance check, withdrawal flows
- [ ] No browser console errors or warnings on staging
- [ ] `STELLAR_NETWORK=mainnet` confirmed in production Vercel env vars
- [ ] `WALLET_ENCRYPTION_KEY` is unique per environment and stored in a password manager
- [ ] Database migrations run on production DB if schema changed:
```bash
psql -d neurowealth -f backend/migrations/001_create_users_table.sql
```
- [ ] CHANGELOG updated
- [ ] Smoke-test production URL after deploy

---

## Rollback Instructions

### Option A — Vercel Dashboard (fastest, ~30 seconds)

1. Go to vercel.com → NeuroWealth project → **Deployments** tab
2. Find the last known-good deployment
3. Click **⋮ → Promote to Production**
4. Verify live URL is restored

### Option B — Git Revert (triggers redeploy)
### Option B — Git Revert (triggers automatic redeploy)

```bash
git checkout main
git revert HEAD # or: git revert <bad-commit-sha>
git push origin main # CI will redeploy automatically
git revert HEAD # or: git revert <bad-commit-sha>
git push origin main # CI redeploys automatically
```

### Option C — Vercel CLI

```bash
vercel rollback --token=$VERCEL_TOKEN
```

---

## Post-Rollback Verification
- [ ] Site loads at production URL

- [ ] Site loads at production URL without errors
- [ ] Send "hi" to NeuroWealth WhatsApp number — bot responds
- [ ] `NEXT_PUBLIC_APP_ENV` shows `production` in browser console
- [ ] Stellar Horizon URL points to `https://horizon.stellar.org` (mainnet)
- [ ] Notify team with: rollback reason, affected versions, resolution ETA
- [ ] `NEXT_PUBLIC_APP_ENV` shows `production` (check via browser → Network → document response headers)
- [ ] Stellar Horizon URL is `https://horizon.stellar.org` (mainnet)
- [ ] Notify team: rollback reason, affected versions, resolution ETA

---

## Docker (self-hosted / alternative deploys)

A `Dockerfile` is included for teams that prefer containerised deploys instead of Vercel.

```bash
# Build image
docker build \
--build-arg NEXT_PUBLIC_APP_ENV=production \
--build-arg NEXT_PUBLIC_APP_URL=https://neurowealth.com \
-t neurowealth-frontend:latest .

# Run container
docker run -p 3000:3000 \
-e NODE_ENV=production \
-e NEXT_PUBLIC_APP_ENV=production \
neurowealth-frontend:latest
```

See `Dockerfile` at the repo root for the full multi-stage build definition.
Loading
Loading