Skip to content
Open
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
6 changes: 6 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ labels: bug
assignees: ""
---

**⚠️ SECURITY VULNERABILITY?**

If you've discovered a security vulnerability, **do not file a public issue**. Instead, please follow our [Security Policy](../../SECURITY.md) to report it privately.

---

## Description

<!-- What happened, and what did you expect to happen instead? -->
Expand Down
6 changes: 6 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ Closes #
- [ ] `npx tsc --noEmit` passes
- [ ] `npm test` passes (or note any skipped/unrelated failures)

## Preview

πŸš€ **Live Preview**: A staging preview will automatically deploy once CI completes. The preview URL will appear as a comment below. Visit it to visually review your changes against the staging backend.

> **Note**: Fork PRs cannot use preview deployments for security reasons. Please run `npm run dev` locally to test.

## Checklist

- [ ] Self-reviewed the diff
Expand Down
139 changes: 139 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
name: Deploy to Production

on:
push:
branches: [main]

concurrency:
group: deployment-${{ github.ref }}
cancel-in-progress: false

jobs:
build:
name: Build
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
build-id: ${{ steps.build.outputs.build-id }}

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build
id: build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_WS_URL: ${{ secrets.NEXT_PUBLIC_WS_URL }}
NEXT_PUBLIC_NETWORK: ${{ secrets.NEXT_PUBLIC_NETWORK }}
NEXT_PUBLIC_SETTLEMENT_CONTRACT: ${{ secrets.NEXT_PUBLIC_SETTLEMENT_CONTRACT }}
NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT: ${{ secrets.NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT }}
run: |
npm run build
echo "build-id=$(date +%s)" >> $GITHUB_OUTPUT

- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: nextjs-build-${{ steps.build.outputs.build-id }}
path: .next
retention-days: 1

deploy:
name: Deploy
runs-on: ubuntu-latest
needs: build
permissions:
contents: read
deployments: write
environment: production

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Download build artifact
uses: actions/download-artifact@v4
with:
name: nextjs-build-${{ needs.build.outputs.build-id }}
path: .next

- name: Deploy to Vercel
id: deploy
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_WS_URL: ${{ secrets.NEXT_PUBLIC_WS_URL }}
NEXT_PUBLIC_NETWORK: ${{ secrets.NEXT_PUBLIC_NETWORK }}
NEXT_PUBLIC_SETTLEMENT_CONTRACT: ${{ secrets.NEXT_PUBLIC_SETTLEMENT_CONTRACT }}
NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT: ${{ secrets.NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT }}
run: |
if [ -z "$VERCEL_TOKEN" ] || [ -z "$VERCEL_PROJECT_ID" ]; then
echo "::warning::Vercel credentials not configured. Skipping Vercel deployment."
echo "deployed=false" >> $GITHUB_OUTPUT
exit 0
fi

npm install -g vercel
DEPLOYMENT_URL=$(vercel deploy --prod \
--token=$VERCEL_TOKEN \
--scope=$VERCEL_ORG_ID \
--project-id=$VERCEL_PROJECT_ID \
2>&1 | tail -1)

echo "deployed=true" >> $GITHUB_OUTPUT
echo "deployment-url=$DEPLOYMENT_URL" >> $GITHUB_OUTPUT

- name: Create deployment status
if: steps.deploy.outputs.deployed == 'true'
uses: actions/github-script@v7
with:
script: |
const deployment = await github.rest.repos.createDeployment({
owner: context.repo.owner,
repo: context.repo.repo,
ref: context.ref,
environment: 'production',
required_contexts: [],
auto_merge: false,
});

await github.rest.repos.createDeploymentStatus({
owner: context.repo.owner,
repo: context.repo.repo,
deployment_id: deployment.data.id,
state: 'success',
environment_url: '${{ steps.deploy.outputs.deployment-url }}',
description: 'Deployment completed successfully',
});

- name: Report deployment summary
if: always()
run: |
echo "## πŸš€ Deployment Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.deploy.outputs.deployed }}" == "true" ]; then
echo "βœ… **Deployment Status**: Success" >> $GITHUB_STEP_SUMMARY
echo "**URL**: ${{ steps.deploy.outputs.deployment-url }}" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ **Deployment Status**: Skipped (Vercel not configured)" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Build ID**: ${{ needs.build.outputs.build-id }}" >> $GITHUB_STEP_SUMMARY
140 changes: 140 additions & 0 deletions .github/workflows/preview-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Deploy PR Preview

on:
pull_request:
types: [opened, reopened, synchronize]
pull_request_target:
types: [opened, reopened, synchronize]

concurrency:
group: preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write

jobs:
deploy-preview:
name: Deploy to Preview
runs-on: ubuntu-latest

steps:
- name: Check if fork PR
id: fork-check
run: |
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
echo "is-fork=true" >> $GITHUB_OUTPUT
echo "fork-owner=${{ github.event.pull_request.head.repo.owner.login }}" >> $GITHUB_OUTPUT
else
echo "is-fork=false" >> $GITHUB_OUTPUT
fi

- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build for preview
id: build
env:
# Use staging/non-production backends for PR previews
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_PREVIEW_API_URL || 'https://api.testnet.example.com' }}
NEXT_PUBLIC_WS_URL: ${{ secrets.NEXT_PUBLIC_PREVIEW_WS_URL || 'wss://api.testnet.example.com/ws' }}
NEXT_PUBLIC_NETWORK: ${{ secrets.NEXT_PUBLIC_PREVIEW_NETWORK || 'testnet' }}
NEXT_PUBLIC_SETTLEMENT_CONTRACT: ${{ secrets.NEXT_PUBLIC_PREVIEW_SETTLEMENT_CONTRACT }}
NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT: ${{ secrets.NEXT_PUBLIC_PREVIEW_SOLVER_REGISTRY_CONTRACT }}
run: |
npm run build
echo "build-timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT

- name: Deploy to Vercel Preview
id: vercel
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_PREVIEW_API_URL || 'https://api.testnet.example.com' }}
NEXT_PUBLIC_WS_URL: ${{ secrets.NEXT_PUBLIC_PREVIEW_WS_URL || 'wss://api.testnet.example.com/ws' }}
NEXT_PUBLIC_NETWORK: ${{ secrets.NEXT_PUBLIC_PREVIEW_NETWORK || 'testnet' }}
NEXT_PUBLIC_SETTLEMENT_CONTRACT: ${{ secrets.NEXT_PUBLIC_PREVIEW_SETTLEMENT_CONTRACT }}
NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT: ${{ secrets.NEXT_PUBLIC_PREVIEW_SOLVER_REGISTRY_CONTRACT }}
run: |
if [ -z "$VERCEL_TOKEN" ] || [ -z "$VERCEL_PROJECT_ID" ]; then
echo "deployment-url=CREDENTIALS_MISSING" >> $GITHUB_OUTPUT
exit 0
fi

npm install -g vercel

# Deploy with PR context for preview environment
PREVIEW_URL=$(vercel deploy \
--token=$VERCEL_TOKEN \
--scope=$VERCEL_ORG_ID \
--project-id=$VERCEL_PROJECT_ID \
--meta pr=${{ github.event.pull_request.number }} \
2>&1 | tail -1 || echo "DEPLOYMENT_FAILED")

if [ "$PREVIEW_URL" != "DEPLOYMENT_FAILED" ] && [ "$PREVIEW_URL" != "CREDENTIALS_MISSING" ]; then
echo "deployment-url=$PREVIEW_URL" >> $GITHUB_OUTPUT
echo "deployment-success=true" >> $GITHUB_OUTPUT
else
echo "deployment-success=false" >> $GITHUB_OUTPUT
fi

- name: Comment on PR - Fork PR
if: steps.fork-check.outputs.is-fork == 'true'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### πŸ”— Preview Deployment\n\n⚠️ **Fork PR detected**: Preview deployments are not available for pull requests from forks. This is a security measure to prevent exposing sensitive deployment credentials.\n\n**To review changes:**\n1. Clone the repository\n2. Checkout this PR's branch\n3. Run \`npm run dev\` locally\n4. Test with your local backend\n\nThank you for contributing! πŸ™`
});

- name: Comment on PR - Preview Ready
if: steps.fork-check.outputs.is-fork == 'false' && steps.vercel.outputs.deployment-success == 'true'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### πŸš€ Preview Deployment Ready\n\nβœ… **Live Preview**: [${{ steps.vercel.outputs.deployment-url }}](${{ steps.vercel.outputs.deployment-url }})\n\n**Backend**: Staging/Testnet\n**Built**: ${{ steps.build.outputs.build-timestamp }}\n\nYou can now view this PR's changes in a live environment. The preview will update automatically as you push new commits.`
});

- name: Comment on PR - Deployment Failed
if: steps.fork-check.outputs.is-fork == 'false' && steps.vercel.outputs.deployment-success == 'false'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### ⚠️ Preview Deployment Failed\n\n❌ **Status**: Deployment encountered an error\n\n**Troubleshooting:**\n- Check that all required secrets are configured in repository settings\n- Verify the build completed successfully in the CI logs\n- Contact maintainers if the issue persists\n\nYou can review the changes by cloning and running locally with \`npm run dev\`.`
});

- name: Comment on PR - Credentials Missing
if: steps.fork-check.outputs.is-fork == 'false' && steps.vercel.outputs.deployment-url == 'CREDENTIALS_MISSING'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `### ℹ️ Preview Deployment Unavailable\n\n**Reason**: Deployment credentials not configured\n\nThe maintainers need to set up Vercel integration by configuring:\n- \`VERCEL_TOKEN\`\n- \`VERCEL_ORG_ID\`\n- \`VERCEL_PROJECT_ID\`\n\nTo review these changes, clone the repository and run \`npm run dev\` locally.`
});
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,68 @@ npm run dev # http://localhost:3000
| `NEXT_PUBLIC_SETTLEMENT_CONTRACT` | Settlement contract ID from `vortex-contract` deployment |
| `NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT` | Solver registry contract ID from `vortex-contract` deployment |

---

## Deployment

### Automated Production Deployment

This repository includes a GitHub Actions workflow (`.github/workflows/deploy.yml`) that automatically deploys the application to Vercel on every merge to `main`.

### Setup Production Deployment

To enable automated deployments, configure the following secrets in your GitHub repository settings:

**Vercel Secrets:**
- `VERCEL_TOKEN` β€” Vercel API token ([create here](https://vercel.com/account/tokens))
- `VERCEL_ORG_ID` β€” Your Vercel organization ID
- `VERCEL_PROJECT_ID` β€” Your Vercel project ID

**Environment Variables (production):**
- `NEXT_PUBLIC_API_URL` β€” Production `vortex-backend` relay URL
- `NEXT_PUBLIC_WS_URL` β€” Production WebSocket URL
- `NEXT_PUBLIC_NETWORK` β€” Production Stellar network
- `NEXT_PUBLIC_SETTLEMENT_CONTRACT` β€” Production contract ID
- `NEXT_PUBLIC_SOLVER_REGISTRY_CONTRACT` β€” Production contract ID

### Deployment Process

1. **Build**: Code is compiled and Next.js build artifacts are generated
2. **Deploy**: Artifacts are deployed to Vercel using production environment variables
3. **Verification**: Deployment status is recorded and summarized in the GitHub Actions log

The workflow runs only on merges to `main`, not on every PR.

### PR Preview Deployments

Pull requests automatically receive live preview deployments to facilitate visual review. Each PR preview:

- **Updates automatically** as new commits are pushed
- **Uses staging backend** (testnet) to isolate testing from production
- **Includes a comment** with the preview URL when deployment succeeds
- **Gracefully handles** fork PRs by explaining local setup instead

#### Fork PR Limitations

For security, pull requests from forks do not receive preview deployments. This prevents exposing deployment credentials. Contributors from forks can:

1. Clone the repository
2. Checkout the PR branch
3. Run `npm run dev` locally with their own `.env.local` configuration
4. Test changes with a local backend instance

#### Setup PR Preview

PR previews require the same Vercel configuration as production deployments (see section above). Additionally, you can configure staging-specific environment variables:

- `NEXT_PUBLIC_PREVIEW_API_URL` β€” Staging backend URL
- `NEXT_PUBLIC_PREVIEW_WS_URL` β€” Staging WebSocket URL
- `NEXT_PUBLIC_PREVIEW_NETWORK` β€” Staging network (e.g., `testnet`)
- `NEXT_PUBLIC_PREVIEW_SETTLEMENT_CONTRACT` β€” Staging contract ID
- `NEXT_PUBLIC_PREVIEW_SOLVER_REGISTRY_CONTRACT` β€” Staging contract ID

If preview-specific variables are not set, the workflow uses sensible defaults pointing to testnet.

### Scripts

| Script | Description |
Expand Down Expand Up @@ -119,6 +181,10 @@ Issues on the Wave tracker use the following complexity labels with correspondin
See the org-wide
[CONTRIBUTING.md](https://github.com/stellar-vortex-protocol/.github/blob/main/CONTRIBUTING.md).

### Security

If you discover a security vulnerability, please report it privately according to our [Security Policy](./SECURITY.md) instead of using the public issue tracker.

## License

[MIT](./LICENSE) Β© 2025 Vortex Protocol Contributors
Loading