feat: add deployment configuration and CI/CD pipeline
Deployment infrastructure:
- Docker:
- Dockerfile.api: Multi-stage build for API
- Dockerfile.web: Multi-stage build for Next.js
- docker-compose.yml: Development orchestration
- docker-compose.prod.yml: Production overrides
- nginx/nginx.conf: Reverse proxy with SSL
- Platform configs:
- vercel.json: Vercel deployment settings
- railway.json: Railway deployment settings
- nixpacks.toml: Nixpacks build config
- CI/CD:
- .github/workflows/deploy.yml: Full pipeline
- Lint and type check
- Unit tests
- Build verification
- Auto-deploy to Vercel (frontend)
- Auto-deploy to Railway (backend)
- Preview deployments for PRs
- Scripts:
- scripts/deploy.sh: Manual deploy helper
- Documentation:
- docs/deployment-guide.md: Complete guide covering
Vercel+Railway, Docker, Kubernetes options
- Environment:
- .env.production.example: All production vars documented
This commit is contained in:
parent
b444974107
commit
8e6d8fba70
|
|
@ -0,0 +1,232 @@
|
||||||
|
# BMAD Web - CI/CD Pipeline
|
||||||
|
# Automated testing and deployment
|
||||||
|
|
||||||
|
name: CI/CD
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, develop]
|
||||||
|
paths:
|
||||||
|
- 'bmad-web/**'
|
||||||
|
- '.github/workflows/deploy.yml'
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'bmad-web/**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
NODE_VERSION: '20'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# ===================
|
||||||
|
# Lint and Type Check
|
||||||
|
# ===================
|
||||||
|
lint:
|
||||||
|
name: Lint & Type Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: bmad-web/package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
- name: Type check
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm run build --workspace=@bmad/core
|
||||||
|
npm run build --workspace=@bmad/ui
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# Unit Tests
|
||||||
|
# ===================
|
||||||
|
test:
|
||||||
|
name: Unit Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: lint
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: bmad-web/package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm test --if-present
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# Build Check
|
||||||
|
# ===================
|
||||||
|
build:
|
||||||
|
name: Build Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: lint
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: bmad-web/package-lock.json
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm ci
|
||||||
|
|
||||||
|
- name: Build packages
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm run build --workspace=@bmad/core
|
||||||
|
npm run build --workspace=@bmad/ui
|
||||||
|
|
||||||
|
- name: Build API
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm run build --workspace=@bmad/api
|
||||||
|
|
||||||
|
- name: Build Web
|
||||||
|
env:
|
||||||
|
NEXT_PUBLIC_API_URL: https://api.example.com
|
||||||
|
NEXT_PUBLIC_WS_URL: wss://api.example.com
|
||||||
|
NEXT_PUBLIC_APP_URL: https://example.com
|
||||||
|
run: |
|
||||||
|
cd bmad-web
|
||||||
|
npm run build --workspace=@bmad/web
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# Deploy Frontend (Vercel)
|
||||||
|
# ===================
|
||||||
|
deploy-frontend:
|
||||||
|
name: Deploy Frontend
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test, build]
|
||||||
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||||
|
environment:
|
||||||
|
name: production
|
||||||
|
url: ${{ steps.deploy.outputs.url }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy to Vercel
|
||||||
|
id: deploy
|
||||||
|
uses: amondnet/vercel-action@v25
|
||||||
|
with:
|
||||||
|
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
||||||
|
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
||||||
|
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||||
|
working-directory: bmad-web/apps/web
|
||||||
|
vercel-args: '--prod'
|
||||||
|
|
||||||
|
- name: Comment PR
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
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: '🚀 Frontend deployed to: ${{ steps.deploy.outputs.url }}'
|
||||||
|
})
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# Deploy Backend (Railway)
|
||||||
|
# ===================
|
||||||
|
deploy-backend:
|
||||||
|
name: Deploy Backend
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [test, build]
|
||||||
|
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install Railway CLI
|
||||||
|
run: npm i -g @railway/cli
|
||||||
|
|
||||||
|
- name: Deploy to Railway
|
||||||
|
env:
|
||||||
|
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
run: |
|
||||||
|
cd bmad-web/apps/api
|
||||||
|
railway up --detach
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# Deploy Preview (PRs)
|
||||||
|
# ===================
|
||||||
|
deploy-preview:
|
||||||
|
name: Deploy Preview
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [lint]
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy Preview to Vercel
|
||||||
|
id: deploy-preview
|
||||||
|
uses: amondnet/vercel-action@v25
|
||||||
|
with:
|
||||||
|
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
||||||
|
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
||||||
|
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||||
|
working-directory: bmad-web/apps/web
|
||||||
|
|
||||||
|
- name: Comment PR with Preview URL
|
||||||
|
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**URL:** ${{ steps.deploy-preview.outputs.preview-url }}\n\n_This preview will be updated with each push to this PR._`
|
||||||
|
})
|
||||||
|
|
||||||
|
# ===================
|
||||||
|
# Notify on Failure
|
||||||
|
# ===================
|
||||||
|
notify-failure:
|
||||||
|
name: Notify Failure
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [deploy-frontend, deploy-backend]
|
||||||
|
if: failure()
|
||||||
|
steps:
|
||||||
|
- name: Send Slack notification
|
||||||
|
uses: 8398a7/action-slack@v3
|
||||||
|
with:
|
||||||
|
status: failure
|
||||||
|
fields: repo,message,commit,author,action,eventName,ref,workflow
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
if: env.SLACK_WEBHOOK_URL != ''
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
# ========================================
|
||||||
|
# BMAD Web - Production Environment
|
||||||
|
# ========================================
|
||||||
|
# Copy this file to .env.production and fill in the values
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Server Configuration
|
||||||
|
# ----------------------------------------
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=4000
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# URLs
|
||||||
|
# ----------------------------------------
|
||||||
|
# Frontend URL (where your app is hosted)
|
||||||
|
FRONTEND_URL=https://bmad.app
|
||||||
|
|
||||||
|
# API URL (for frontend to connect)
|
||||||
|
NEXT_PUBLIC_API_URL=https://api.bmad.app
|
||||||
|
NEXT_PUBLIC_WS_URL=wss://api.bmad.app
|
||||||
|
NEXT_PUBLIC_APP_URL=https://bmad.app
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Authentication
|
||||||
|
# ----------------------------------------
|
||||||
|
# Generate with: openssl rand -base64 32
|
||||||
|
JWT_SECRET=your-super-secret-jwt-key-minimum-32-characters
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Database
|
||||||
|
# ----------------------------------------
|
||||||
|
# PostgreSQL connection string
|
||||||
|
# Format: postgresql://USER:PASSWORD@HOST:PORT/DATABASE
|
||||||
|
DATABASE_URL=postgresql://bmad:password@localhost:5432/bmad_web
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Redis
|
||||||
|
# ----------------------------------------
|
||||||
|
# Redis connection string
|
||||||
|
# Format: redis://[:PASSWORD@]HOST:PORT
|
||||||
|
REDIS_URL=redis://localhost:6379
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# BMAD Core
|
||||||
|
# ----------------------------------------
|
||||||
|
# Path to BMAD source (for agent definitions)
|
||||||
|
BMAD_ROOT=/app/bmad-core
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# AI Providers
|
||||||
|
# ----------------------------------------
|
||||||
|
# OpenAI API Key (for GPT models)
|
||||||
|
OPENAI_API_KEY=sk-your-openai-api-key
|
||||||
|
|
||||||
|
# Anthropic API Key (for Claude models)
|
||||||
|
ANTHROPIC_API_KEY=sk-ant-your-anthropic-api-key
|
||||||
|
|
||||||
|
# Default model to use
|
||||||
|
DEFAULT_AI_MODEL=gpt-4-turbo-preview
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Stripe (Billing)
|
||||||
|
# ----------------------------------------
|
||||||
|
STRIPE_SECRET_KEY=sk_live_your-stripe-secret-key
|
||||||
|
STRIPE_WEBHOOK_SECRET=whsec_your-webhook-secret
|
||||||
|
|
||||||
|
# Price IDs from Stripe Dashboard
|
||||||
|
STRIPE_PRICE_STARTER_MONTHLY=price_xxx
|
||||||
|
STRIPE_PRICE_STARTER_YEARLY=price_xxx
|
||||||
|
STRIPE_PRICE_PRO_MONTHLY=price_xxx
|
||||||
|
STRIPE_PRICE_PRO_YEARLY=price_xxx
|
||||||
|
STRIPE_PRICE_TEAM_MONTHLY=price_xxx
|
||||||
|
STRIPE_PRICE_TEAM_YEARLY=price_xxx
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Email (SendGrid/SMTP)
|
||||||
|
# ----------------------------------------
|
||||||
|
SMTP_HOST=smtp.sendgrid.net
|
||||||
|
SMTP_PORT=587
|
||||||
|
SMTP_USER=apikey
|
||||||
|
SMTP_PASS=SG.your-sendgrid-api-key
|
||||||
|
EMAIL_FROM=noreply@bmad.app
|
||||||
|
EMAIL_FROM_NAME=BMAD
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Storage (S3/MinIO)
|
||||||
|
# ----------------------------------------
|
||||||
|
S3_ENDPOINT=https://s3.amazonaws.com
|
||||||
|
S3_BUCKET=bmad-artifacts
|
||||||
|
S3_ACCESS_KEY=your-access-key
|
||||||
|
S3_SECRET_KEY=your-secret-key
|
||||||
|
S3_REGION=us-east-1
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Monitoring
|
||||||
|
# ----------------------------------------
|
||||||
|
# Sentry DSN for error tracking
|
||||||
|
SENTRY_DSN=https://xxx@sentry.io/xxx
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Analytics (Optional)
|
||||||
|
# ----------------------------------------
|
||||||
|
NEXT_PUBLIC_MIXPANEL_TOKEN=your-mixpanel-token
|
||||||
|
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Feature Flags
|
||||||
|
# ----------------------------------------
|
||||||
|
NEXT_PUBLIC_ENABLE_BILLING=true
|
||||||
|
NEXT_PUBLIC_ENABLE_ANALYTICS=true
|
||||||
|
ENABLE_RATE_LIMITING=true
|
||||||
|
|
||||||
|
# ----------------------------------------
|
||||||
|
# Rate Limiting
|
||||||
|
# ----------------------------------------
|
||||||
|
RATE_LIMIT_WINDOW_MS=900000
|
||||||
|
RATE_LIMIT_MAX_REQUESTS=100
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
# BMAD API Dockerfile
|
||||||
|
# Multi-stage build for optimized production image
|
||||||
|
|
||||||
|
# Stage 1: Dependencies
|
||||||
|
FROM node:20-alpine AS deps
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install dependencies needed for native modules
|
||||||
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
COPY apps/api/package.json ./apps/api/
|
||||||
|
COPY packages/bmad-core/package.json ./packages/bmad-core/
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm ci --workspace=@bmad/api --workspace=@bmad/core
|
||||||
|
|
||||||
|
# Stage 2: Builder
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy dependencies
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY --from=deps /app/apps/api/node_modules ./apps/api/node_modules
|
||||||
|
COPY --from=deps /app/packages/bmad-core/node_modules ./packages/bmad-core/node_modules
|
||||||
|
|
||||||
|
# Copy source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build
|
||||||
|
RUN npm run build --workspace=@bmad/core
|
||||||
|
RUN npm run build --workspace=@bmad/api
|
||||||
|
|
||||||
|
# Stage 3: Runner
|
||||||
|
FROM node:20-alpine AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Set production environment
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=4000
|
||||||
|
|
||||||
|
# Create non-root user
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 bmad
|
||||||
|
|
||||||
|
# Copy built application
|
||||||
|
COPY --from=builder /app/apps/api/dist ./dist
|
||||||
|
COPY --from=builder /app/apps/api/package.json ./
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder /app/packages/bmad-core/dist ./packages/bmad-core/dist
|
||||||
|
COPY --from=builder /app/packages/bmad-core/package.json ./packages/bmad-core/
|
||||||
|
|
||||||
|
# Copy BMAD source for agent definitions
|
||||||
|
COPY --from=builder /app/../src ./bmad-src
|
||||||
|
|
||||||
|
# Set ownership
|
||||||
|
RUN chown -R bmad:nodejs /app
|
||||||
|
|
||||||
|
# Switch to non-root user
|
||||||
|
USER bmad
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 4000
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:4000/health || exit 1
|
||||||
|
|
||||||
|
# Start server
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
# BMAD Web Frontend Dockerfile
|
||||||
|
# Multi-stage build for Next.js
|
||||||
|
|
||||||
|
# Stage 1: Dependencies
|
||||||
|
FROM node:20-alpine AS deps
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apk add --no-cache libc6-compat
|
||||||
|
|
||||||
|
COPY package.json package-lock.json* ./
|
||||||
|
COPY apps/web/package.json ./apps/web/
|
||||||
|
COPY packages/ui/package.json ./packages/ui/
|
||||||
|
COPY packages/bmad-core/package.json ./packages/bmad-core/
|
||||||
|
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Stage 2: Builder
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build arguments for environment variables
|
||||||
|
ARG NEXT_PUBLIC_API_URL
|
||||||
|
ARG NEXT_PUBLIC_WS_URL
|
||||||
|
ARG NEXT_PUBLIC_APP_URL
|
||||||
|
|
||||||
|
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
|
||||||
|
ENV NEXT_PUBLIC_WS_URL=$NEXT_PUBLIC_WS_URL
|
||||||
|
ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL
|
||||||
|
|
||||||
|
# Build packages first
|
||||||
|
RUN npm run build --workspace=@bmad/core
|
||||||
|
RUN npm run build --workspace=@bmad/ui
|
||||||
|
|
||||||
|
# Build Next.js app
|
||||||
|
RUN npm run build --workspace=@bmad/web
|
||||||
|
|
||||||
|
# Stage 3: Runner
|
||||||
|
FROM node:20-alpine AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=3000
|
||||||
|
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
|
# Copy built application
|
||||||
|
COPY --from=builder /app/apps/web/public ./public
|
||||||
|
COPY --from=builder /app/apps/web/.next/standalone ./
|
||||||
|
COPY --from=builder /app/apps/web/.next/static ./.next/static
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENV HOSTNAME="0.0.0.0"
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Nixpacks configuration for Railway
|
||||||
|
|
||||||
|
[phases.setup]
|
||||||
|
nixPkgs = ["nodejs_20", "npm"]
|
||||||
|
|
||||||
|
[phases.install]
|
||||||
|
cmds = ["npm ci"]
|
||||||
|
|
||||||
|
[phases.build]
|
||||||
|
cmds = ["npm run build"]
|
||||||
|
|
||||||
|
[start]
|
||||||
|
cmd = "npm start"
|
||||||
|
|
||||||
|
[variables]
|
||||||
|
NODE_ENV = "production"
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://railway.app/railway.schema.json",
|
||||||
|
"build": {
|
||||||
|
"builder": "NIXPACKS",
|
||||||
|
"buildCommand": "npm run build"
|
||||||
|
},
|
||||||
|
"deploy": {
|
||||||
|
"startCommand": "npm start",
|
||||||
|
"healthcheckPath": "/health",
|
||||||
|
"healthcheckTimeout": 30,
|
||||||
|
"restartPolicyType": "ON_FAILURE",
|
||||||
|
"restartPolicyMaxRetries": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,11 +2,64 @@
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
transpilePackages: ['@bmad/core', '@bmad/ui'],
|
transpilePackages: ['@bmad/core', '@bmad/ui'],
|
||||||
|
|
||||||
|
// Enable standalone output for Docker
|
||||||
|
output: 'standalone',
|
||||||
|
|
||||||
experimental: {
|
experimental: {
|
||||||
serverComponentsExternalPackages: ['@bmad/core'],
|
serverComponentsExternalPackages: ['@bmad/core'],
|
||||||
},
|
},
|
||||||
|
|
||||||
images: {
|
images: {
|
||||||
domains: ['avatars.githubusercontent.com'],
|
domains: ['avatars.githubusercontent.com'],
|
||||||
|
// Allow images from any domain in production
|
||||||
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: '**',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
|
||||||
|
// Environment variables available at build time
|
||||||
|
env: {
|
||||||
|
NEXT_PUBLIC_APP_VERSION: process.env.npm_package_version || '1.0.0',
|
||||||
|
},
|
||||||
|
|
||||||
|
// Headers for security
|
||||||
|
async headers() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
source: '/(.*)',
|
||||||
|
headers: [
|
||||||
|
{
|
||||||
|
key: 'X-DNS-Prefetch-Control',
|
||||||
|
value: 'on',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'X-Frame-Options',
|
||||||
|
value: 'SAMEORIGIN',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'X-Content-Type-Options',
|
||||||
|
value: 'nosniff',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
// Rewrites for API proxy (optional, for development)
|
||||||
|
async rewrites() {
|
||||||
|
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000';
|
||||||
|
return process.env.NODE_ENV === 'development'
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
source: '/api/:path*',
|
||||||
|
destination: `${apiUrl}/api/:path*`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://openapi.vercel.sh/vercel.json",
|
||||||
|
"framework": "nextjs",
|
||||||
|
"buildCommand": "cd ../.. && npm run build --workspace=@bmad/web",
|
||||||
|
"installCommand": "cd ../.. && npm ci",
|
||||||
|
"outputDirectory": ".next",
|
||||||
|
"regions": ["gru1"],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"source": "/(.*)",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "X-Frame-Options",
|
||||||
|
"value": "DENY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "X-Content-Type-Options",
|
||||||
|
"value": "nosniff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "X-XSS-Protection",
|
||||||
|
"value": "1; mode=block"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "Referrer-Policy",
|
||||||
|
"value": "strict-origin-when-cross-origin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "/api/(.*)",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "Cache-Control",
|
||||||
|
"value": "no-store, max-age=0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "/_next/static/(.*)",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "Cache-Control",
|
||||||
|
"value": "public, max-age=31536000, immutable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rewrites": [
|
||||||
|
{
|
||||||
|
"source": "/api/:path*",
|
||||||
|
"destination": "${NEXT_PUBLIC_API_URL}/api/:path*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
# BMAD Web - Production Overrides
|
||||||
|
# Use with: docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
|
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
|
||||||
|
# Don't expose port in production
|
||||||
|
ports: []
|
||||||
|
|
||||||
|
redis:
|
||||||
|
restart: always
|
||||||
|
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-}
|
||||||
|
ports: []
|
||||||
|
|
||||||
|
api:
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET is required}
|
||||||
|
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required}
|
||||||
|
REDIS_URL: ${REDIS_URL:?REDIS_URL is required}
|
||||||
|
# Remove volume mounts in production
|
||||||
|
volumes: []
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: '1'
|
||||||
|
memory: 1G
|
||||||
|
reservations:
|
||||||
|
cpus: '0.5'
|
||||||
|
memory: 512M
|
||||||
|
|
||||||
|
web:
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: '0.5'
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
cpus: '0.25'
|
||||||
|
memory: 256M
|
||||||
|
|
||||||
|
# Nginx Reverse Proxy for production
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: bmad-nginx
|
||||||
|
restart: always
|
||||||
|
depends_on:
|
||||||
|
- web
|
||||||
|
- api
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||||
|
- ./nginx/ssl:/etc/nginx/ssl:ro
|
||||||
|
- nginx_cache:/var/cache/nginx
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "nginx", "-t"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
nginx_cache:
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
# BMAD Web - Docker Compose
|
||||||
|
# Development and production orchestration
|
||||||
|
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# PostgreSQL Database
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: bmad-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-bmad}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-bmad_dev_password}
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:-bmad_web}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-bmad}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# Redis Cache
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: bmad-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# API Backend
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.api
|
||||||
|
container_name: bmad-api
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: ${NODE_ENV:-development}
|
||||||
|
PORT: 4000
|
||||||
|
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:3000}
|
||||||
|
JWT_SECRET: ${JWT_SECRET:-dev-secret-change-in-production}
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER:-bmad}:${POSTGRES_PASSWORD:-bmad_dev_password}@postgres:5432/${POSTGRES_DB:-bmad_web}
|
||||||
|
REDIS_URL: redis://redis:6379
|
||||||
|
BMAD_ROOT: /app/bmad-src
|
||||||
|
OPENAI_API_KEY: ${OPENAI_API_KEY:-}
|
||||||
|
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||||
|
ports:
|
||||||
|
- "4000:4000"
|
||||||
|
volumes:
|
||||||
|
# For development: hot reload
|
||||||
|
- ./apps/api/src:/app/src:ro
|
||||||
|
# BMAD source for agent definitions
|
||||||
|
- ../src:/app/bmad-src:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4000/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
# Web Frontend
|
||||||
|
web:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.web
|
||||||
|
args:
|
||||||
|
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:4000}
|
||||||
|
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-ws://localhost:4000}
|
||||||
|
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
|
||||||
|
container_name: bmad-web
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
environment:
|
||||||
|
NODE_ENV: ${NODE_ENV:-development}
|
||||||
|
PORT: 3000
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
redis_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
name: bmad-network
|
||||||
|
|
@ -0,0 +1,566 @@
|
||||||
|
# BMAD Web - Guia de Deploy
|
||||||
|
|
||||||
|
Este guia cobre todas as opcoes de deploy para a aplicacao BMAD Web.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sumario
|
||||||
|
|
||||||
|
1. [Arquitetura de Deploy](#arquitetura-de-deploy)
|
||||||
|
2. [Opcao 1: Vercel + Railway (Recomendado)](#opcao-1-vercel--railway-recomendado)
|
||||||
|
3. [Opcao 2: Docker Compose (Self-hosted)](#opcao-2-docker-compose-self-hosted)
|
||||||
|
4. [Opcao 3: Kubernetes](#opcao-3-kubernetes)
|
||||||
|
5. [Configuracao de Banco de Dados](#configuracao-de-banco-de-dados)
|
||||||
|
6. [Variaveis de Ambiente](#variaveis-de-ambiente)
|
||||||
|
7. [CI/CD com GitHub Actions](#cicd-com-github-actions)
|
||||||
|
8. [Monitoramento](#monitoramento)
|
||||||
|
9. [Checklist de Producao](#checklist-de-producao)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Arquitetura de Deploy
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ PRODUCAO │
|
||||||
|
├─────────────────────────────────────────────────────────────────────┤
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
|
||||||
|
│ │ Vercel │ │ Railway │ │ Supabase │ │
|
||||||
|
│ │ (Next.js) │◄───────►│ (API) │◄───────►│ (Postgres)│ │
|
||||||
|
│ │ │ │ │ │ │ │
|
||||||
|
│ │ Frontend │ REST │ Backend │ SQL │ Database │ │
|
||||||
|
│ │ + CDN │ + WS │ + Socket │ │ + Auth │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ └────────────┘ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ▼ ▼ ▼ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
|
||||||
|
│ │ Cloudflare │ │ Upstash │ │ S3 │ │
|
||||||
|
│ │ (DNS) │ │ (Redis) │ │ (Assets) │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ └────────────┘ │
|
||||||
|
│ │
|
||||||
|
└─────────────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Opcao 1: Vercel + Railway (Recomendado)
|
||||||
|
|
||||||
|
A opcao mais simples para comecar. Zero configuracao de infraestrutura.
|
||||||
|
|
||||||
|
### 1.1 Deploy do Frontend (Vercel)
|
||||||
|
|
||||||
|
#### Passo 1: Conectar repositorio
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Instalar Vercel CLI
|
||||||
|
npm i -g vercel
|
||||||
|
|
||||||
|
# Login
|
||||||
|
vercel login
|
||||||
|
|
||||||
|
# Na pasta bmad-web/apps/web
|
||||||
|
cd bmad-web/apps/web
|
||||||
|
vercel
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Passo 2: Configurar no Dashboard Vercel
|
||||||
|
|
||||||
|
1. Acesse https://vercel.com/dashboard
|
||||||
|
2. Import o repositorio do GitHub
|
||||||
|
3. Configure:
|
||||||
|
- **Framework Preset**: Next.js
|
||||||
|
- **Root Directory**: `bmad-web/apps/web`
|
||||||
|
- **Build Command**: `npm run build`
|
||||||
|
- **Output Directory**: `.next`
|
||||||
|
|
||||||
|
#### Passo 3: Variaveis de Ambiente
|
||||||
|
|
||||||
|
No dashboard Vercel, adicione:
|
||||||
|
|
||||||
|
```
|
||||||
|
NEXT_PUBLIC_API_URL=https://sua-api.railway.app
|
||||||
|
NEXT_PUBLIC_WS_URL=wss://sua-api.railway.app
|
||||||
|
NEXT_PUBLIC_APP_URL=https://seu-app.vercel.app
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Passo 4: Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Deploy de producao
|
||||||
|
vercel --prod
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.2 Deploy da API (Railway)
|
||||||
|
|
||||||
|
#### Passo 1: Criar projeto Railway
|
||||||
|
|
||||||
|
1. Acesse https://railway.app
|
||||||
|
2. New Project > Deploy from GitHub repo
|
||||||
|
3. Selecione o repositorio
|
||||||
|
|
||||||
|
#### Passo 2: Configurar servico
|
||||||
|
|
||||||
|
No dashboard Railway:
|
||||||
|
|
||||||
|
1. **Root Directory**: `bmad-web/apps/api`
|
||||||
|
2. **Build Command**: `npm run build`
|
||||||
|
3. **Start Command**: `npm start`
|
||||||
|
|
||||||
|
#### Passo 3: Variaveis de Ambiente
|
||||||
|
|
||||||
|
```
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=4000
|
||||||
|
FRONTEND_URL=https://seu-app.vercel.app
|
||||||
|
JWT_SECRET=sua-chave-super-secreta-aqui
|
||||||
|
DATABASE_URL=postgresql://...
|
||||||
|
REDIS_URL=redis://...
|
||||||
|
BMAD_ROOT=/app/../../..
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Passo 4: Adicionar Postgres (Railway)
|
||||||
|
|
||||||
|
1. No projeto Railway, clique em "New"
|
||||||
|
2. Selecione "Database" > "PostgreSQL"
|
||||||
|
3. Copie a DATABASE_URL gerada
|
||||||
|
|
||||||
|
#### Passo 5: Adicionar Redis (Upstash)
|
||||||
|
|
||||||
|
1. Acesse https://upstash.com
|
||||||
|
2. Crie um banco Redis
|
||||||
|
3. Copie a REDIS_URL
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 1.3 Comandos Rapidos (Vercel + Railway)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Frontend
|
||||||
|
cd bmad-web/apps/web
|
||||||
|
vercel --prod
|
||||||
|
|
||||||
|
# Backend (Railway CLI)
|
||||||
|
npm i -g @railway/cli
|
||||||
|
railway login
|
||||||
|
cd bmad-web/apps/api
|
||||||
|
railway up
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Opcao 2: Docker Compose (Self-hosted)
|
||||||
|
|
||||||
|
Para quem quer controle total ou rodar on-premise.
|
||||||
|
|
||||||
|
### 2.1 Arquivos Docker
|
||||||
|
|
||||||
|
Os arquivos ja estao criados:
|
||||||
|
- `bmad-web/Dockerfile.web` - Frontend
|
||||||
|
- `bmad-web/Dockerfile.api` - Backend
|
||||||
|
- `bmad-web/docker-compose.yml` - Orquestracao
|
||||||
|
- `bmad-web/docker-compose.prod.yml` - Producao
|
||||||
|
|
||||||
|
### 2.2 Build e Run Local
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd bmad-web
|
||||||
|
|
||||||
|
# Desenvolvimento
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Producao
|
||||||
|
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 Deploy em VPS (DigitalOcean, Hetzner, etc.)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. SSH na VPS
|
||||||
|
ssh root@seu-servidor
|
||||||
|
|
||||||
|
# 2. Instalar Docker
|
||||||
|
curl -fsSL https://get.docker.com | sh
|
||||||
|
|
||||||
|
# 3. Clonar repositorio
|
||||||
|
git clone https://github.com/seu-usuario/BMAD-METHOD.git
|
||||||
|
cd BMAD-METHOD/bmad-web
|
||||||
|
|
||||||
|
# 4. Configurar ambiente
|
||||||
|
cp .env.example .env
|
||||||
|
nano .env # Editar variaveis
|
||||||
|
|
||||||
|
# 5. Subir servicos
|
||||||
|
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
||||||
|
|
||||||
|
# 6. Configurar Nginx (proxy reverso)
|
||||||
|
apt install nginx
|
||||||
|
# Copiar config do nginx.conf
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4 Com Traefik (HTTPS automatico)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Usar docker-compose.traefik.yml para HTTPS automatico
|
||||||
|
docker-compose -f docker-compose.yml -f docker-compose.traefik.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Opcao 3: Kubernetes
|
||||||
|
|
||||||
|
Para escala enterprise.
|
||||||
|
|
||||||
|
### 3.1 Estrutura
|
||||||
|
|
||||||
|
```
|
||||||
|
bmad-web/k8s/
|
||||||
|
├── namespace.yaml
|
||||||
|
├── configmap.yaml
|
||||||
|
├── secrets.yaml
|
||||||
|
├── web-deployment.yaml
|
||||||
|
├── api-deployment.yaml
|
||||||
|
├── postgres-deployment.yaml
|
||||||
|
├── redis-deployment.yaml
|
||||||
|
├── ingress.yaml
|
||||||
|
└── hpa.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Criar namespace
|
||||||
|
kubectl apply -f k8s/namespace.yaml
|
||||||
|
|
||||||
|
# Aplicar configs
|
||||||
|
kubectl apply -f k8s/
|
||||||
|
|
||||||
|
# Verificar status
|
||||||
|
kubectl get pods -n bmad
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuracao de Banco de Dados
|
||||||
|
|
||||||
|
### Opcao A: Supabase (Recomendado)
|
||||||
|
|
||||||
|
1. Crie conta em https://supabase.com
|
||||||
|
2. Crie novo projeto
|
||||||
|
3. Copie a connection string:
|
||||||
|
```
|
||||||
|
DATABASE_URL=postgresql://postgres:[senha]@db.[ref].supabase.co:5432/postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
### Opcao B: PlanetScale (MySQL)
|
||||||
|
|
||||||
|
1. Crie conta em https://planetscale.com
|
||||||
|
2. Crie database
|
||||||
|
3. Copie connection string
|
||||||
|
|
||||||
|
### Opcao C: Neon (Postgres Serverless)
|
||||||
|
|
||||||
|
1. Crie conta em https://neon.tech
|
||||||
|
2. Crie projeto
|
||||||
|
3. Copie connection string
|
||||||
|
|
||||||
|
### Migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd bmad-web/apps/api
|
||||||
|
|
||||||
|
# Gerar cliente Prisma
|
||||||
|
npx prisma generate
|
||||||
|
|
||||||
|
# Push schema para banco
|
||||||
|
npx prisma db push
|
||||||
|
|
||||||
|
# Ou usar migrations
|
||||||
|
npx prisma migrate deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Variaveis de Ambiente
|
||||||
|
|
||||||
|
### Frontend (.env.local)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# API
|
||||||
|
NEXT_PUBLIC_API_URL=https://api.bmad.app
|
||||||
|
NEXT_PUBLIC_WS_URL=wss://api.bmad.app
|
||||||
|
|
||||||
|
# App
|
||||||
|
NEXT_PUBLIC_APP_URL=https://bmad.app
|
||||||
|
NEXT_PUBLIC_APP_NAME=BMAD
|
||||||
|
|
||||||
|
# Analytics (opcional)
|
||||||
|
NEXT_PUBLIC_MIXPANEL_TOKEN=xxx
|
||||||
|
NEXT_PUBLIC_GA_ID=G-xxx
|
||||||
|
|
||||||
|
# Feature Flags (opcional)
|
||||||
|
NEXT_PUBLIC_ENABLE_BILLING=true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backend (.env)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Server
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=4000
|
||||||
|
|
||||||
|
# URLs
|
||||||
|
FRONTEND_URL=https://bmad.app
|
||||||
|
|
||||||
|
# Auth
|
||||||
|
JWT_SECRET=sua-chave-jwt-muito-secreta-minimo-32-chars
|
||||||
|
|
||||||
|
# Database
|
||||||
|
DATABASE_URL=postgresql://user:pass@host:5432/bmad
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
REDIS_URL=redis://default:pass@host:6379
|
||||||
|
|
||||||
|
# BMAD Core
|
||||||
|
BMAD_ROOT=/app/bmad-core
|
||||||
|
|
||||||
|
# AI Providers
|
||||||
|
OPENAI_API_KEY=sk-xxx
|
||||||
|
ANTHROPIC_API_KEY=sk-ant-xxx
|
||||||
|
|
||||||
|
# Stripe (billing)
|
||||||
|
STRIPE_SECRET_KEY=sk_live_xxx
|
||||||
|
STRIPE_WEBHOOK_SECRET=whsec_xxx
|
||||||
|
|
||||||
|
# Email (opcional)
|
||||||
|
SMTP_HOST=smtp.sendgrid.net
|
||||||
|
SMTP_USER=apikey
|
||||||
|
SMTP_PASS=SG.xxx
|
||||||
|
|
||||||
|
# Monitoring (opcional)
|
||||||
|
SENTRY_DSN=https://xxx@sentry.io/xxx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gerar JWT_SECRET Seguro
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openssl rand -base64 32
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD com GitHub Actions
|
||||||
|
|
||||||
|
### Arquivo: `.github/workflows/deploy.yml`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Deploy
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: cd bmad-web && npm ci
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: cd bmad-web && npm run lint
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: cd bmad-web && npm test
|
||||||
|
|
||||||
|
deploy-frontend:
|
||||||
|
needs: test
|
||||||
|
if: github.ref == 'refs/heads/main'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: amondnet/vercel-action@v25
|
||||||
|
with:
|
||||||
|
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
||||||
|
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
||||||
|
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||||
|
working-directory: bmad-web/apps/web
|
||||||
|
vercel-args: '--prod'
|
||||||
|
|
||||||
|
deploy-backend:
|
||||||
|
needs: test
|
||||||
|
if: github.ref == 'refs/heads/main'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: railwayapp/railway-action@v1
|
||||||
|
with:
|
||||||
|
railway-token: ${{ secrets.RAILWAY_TOKEN }}
|
||||||
|
service: api
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Monitoramento
|
||||||
|
|
||||||
|
### Sentry (Error Tracking)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Instalar
|
||||||
|
npm install @sentry/nextjs @sentry/node
|
||||||
|
|
||||||
|
# Configurar em next.config.js e api/src/index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Uptime Monitoring
|
||||||
|
|
||||||
|
- **Better Uptime**: https://betteruptime.com
|
||||||
|
- **UptimeRobot**: https://uptimerobot.com
|
||||||
|
|
||||||
|
Endpoints para monitorar:
|
||||||
|
- `https://bmad.app` (frontend)
|
||||||
|
- `https://api.bmad.app/health` (backend)
|
||||||
|
|
||||||
|
### Analytics
|
||||||
|
|
||||||
|
- **Mixpanel**: Eventos de produto
|
||||||
|
- **Google Analytics**: Trafego
|
||||||
|
- **PostHog**: Open-source alternativa
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checklist de Producao
|
||||||
|
|
||||||
|
### Seguranca
|
||||||
|
- [ ] JWT_SECRET forte (32+ chars)
|
||||||
|
- [ ] HTTPS em todos os endpoints
|
||||||
|
- [ ] Rate limiting configurado
|
||||||
|
- [ ] CORS configurado corretamente
|
||||||
|
- [ ] Headers de seguranca (helmet)
|
||||||
|
- [ ] Variaveis sensiveis em secrets manager
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- [ ] CDN para assets estaticos
|
||||||
|
- [ ] Cache Redis funcionando
|
||||||
|
- [ ] Compressao gzip habilitada
|
||||||
|
- [ ] Images otimizadas (next/image)
|
||||||
|
- [ ] Bundle size otimizado
|
||||||
|
|
||||||
|
### Banco de Dados
|
||||||
|
- [ ] Backups automaticos configurados
|
||||||
|
- [ ] Connection pooling (PgBouncer)
|
||||||
|
- [ ] Indices criados para queries frequentes
|
||||||
|
- [ ] SSL habilitado na conexao
|
||||||
|
|
||||||
|
### Monitoramento
|
||||||
|
- [ ] Error tracking (Sentry)
|
||||||
|
- [ ] Uptime monitoring
|
||||||
|
- [ ] Log aggregation
|
||||||
|
- [ ] Alertas configurados
|
||||||
|
|
||||||
|
### Legal/Compliance
|
||||||
|
- [ ] Termos de Servico
|
||||||
|
- [ ] Politica de Privacidade
|
||||||
|
- [ ] Cookie consent
|
||||||
|
- [ ] LGPD/GDPR compliance
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Erro: "WebSocket connection failed"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verificar se WebSocket esta habilitado no Railway/Vercel
|
||||||
|
# Railway: ja suporta nativamente
|
||||||
|
# Vercel: usar Vercel Serverless Functions com upgrade
|
||||||
|
```
|
||||||
|
|
||||||
|
### Erro: "Database connection timeout"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verificar DATABASE_URL
|
||||||
|
# Adicionar ?connect_timeout=10&pool_timeout=10
|
||||||
|
DATABASE_URL=postgresql://...?connect_timeout=10
|
||||||
|
```
|
||||||
|
|
||||||
|
### Erro: "JWT invalid"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verificar se JWT_SECRET e o mesmo em todos os servicos
|
||||||
|
# Verificar timezone dos servidores
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build falha no Vercel
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verificar se todas as deps estao no package.json
|
||||||
|
# Verificar se NEXT_PUBLIC_* estao configuradas
|
||||||
|
# Verificar Root Directory
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comandos Uteis
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Logs da API (Railway)
|
||||||
|
railway logs
|
||||||
|
|
||||||
|
# Logs do Frontend (Vercel)
|
||||||
|
vercel logs
|
||||||
|
|
||||||
|
# SSH no container Docker
|
||||||
|
docker exec -it bmad-api sh
|
||||||
|
|
||||||
|
# Prisma Studio (visualizar banco)
|
||||||
|
npx prisma studio
|
||||||
|
|
||||||
|
# Reset do banco (CUIDADO!)
|
||||||
|
npx prisma migrate reset
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Custos Estimados
|
||||||
|
|
||||||
|
### Startup (0-1000 usuarios)
|
||||||
|
|
||||||
|
| Servico | Custo/mes |
|
||||||
|
|---------|-----------|
|
||||||
|
| Vercel (Hobby) | $0 |
|
||||||
|
| Railway (Starter) | $5 |
|
||||||
|
| Supabase (Free) | $0 |
|
||||||
|
| Upstash (Free) | $0 |
|
||||||
|
| **Total** | **$5/mes** |
|
||||||
|
|
||||||
|
### Growth (1000-10000 usuarios)
|
||||||
|
|
||||||
|
| Servico | Custo/mes |
|
||||||
|
|---------|-----------|
|
||||||
|
| Vercel (Pro) | $20 |
|
||||||
|
| Railway (Pro) | $20 |
|
||||||
|
| Supabase (Pro) | $25 |
|
||||||
|
| Upstash (Pay-as-go) | $10 |
|
||||||
|
| **Total** | **$75/mes** |
|
||||||
|
|
||||||
|
### Scale (10000+ usuarios)
|
||||||
|
|
||||||
|
| Servico | Custo/mes |
|
||||||
|
|---------|-----------|
|
||||||
|
| Vercel (Enterprise) | $150+ |
|
||||||
|
| Railway (Team) | $50+ |
|
||||||
|
| Supabase (Team) | $599+ |
|
||||||
|
| Redis (Managed) | $50+ |
|
||||||
|
| **Total** | **$850+/mes** |
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
# BMAD Web - Nginx Configuration
|
||||||
|
# Production reverse proxy with SSL
|
||||||
|
|
||||||
|
user nginx;
|
||||||
|
worker_processes auto;
|
||||||
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
|
events {
|
||||||
|
worker_connections 1024;
|
||||||
|
use epoll;
|
||||||
|
multi_accept on;
|
||||||
|
}
|
||||||
|
|
||||||
|
http {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
default_type application/octet-stream;
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
sendfile on;
|
||||||
|
tcp_nopush on;
|
||||||
|
tcp_nodelay on;
|
||||||
|
keepalive_timeout 65;
|
||||||
|
types_hash_max_size 2048;
|
||||||
|
|
||||||
|
# Gzip
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_proxied any;
|
||||||
|
gzip_comp_level 6;
|
||||||
|
gzip_types text/plain text/css text/xml application/json application/javascript
|
||||||
|
application/rss+xml application/atom+xml image/svg+xml;
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
|
|
||||||
|
# Rate limiting
|
||||||
|
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
|
||||||
|
limit_req_zone $binary_remote_addr zone=web:10m rate=30r/s;
|
||||||
|
|
||||||
|
# Upstream servers
|
||||||
|
upstream web_upstream {
|
||||||
|
server web:3000;
|
||||||
|
keepalive 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
upstream api_upstream {
|
||||||
|
server api:4000;
|
||||||
|
keepalive 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Redirect HTTP to HTTPS
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main HTTPS server
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name bmad.app www.bmad.app;
|
||||||
|
|
||||||
|
# SSL Configuration
|
||||||
|
ssl_certificate /etc/nginx/ssl/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/privkey.pem;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_cache shared:SSL:50m;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
|
||||||
|
# Modern SSL configuration
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
|
||||||
|
ssl_prefer_server_ciphers off;
|
||||||
|
|
||||||
|
# HSTS
|
||||||
|
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||||
|
|
||||||
|
# Frontend
|
||||||
|
location / {
|
||||||
|
limit_req zone=web burst=50 nodelay;
|
||||||
|
|
||||||
|
proxy_pass http://web_upstream;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# API
|
||||||
|
location /api {
|
||||||
|
limit_req zone=api burst=20 nodelay;
|
||||||
|
|
||||||
|
proxy_pass http://api_upstream;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# Timeouts for long-running requests
|
||||||
|
proxy_connect_timeout 60s;
|
||||||
|
proxy_send_timeout 60s;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# WebSocket for Socket.io
|
||||||
|
location /socket.io {
|
||||||
|
proxy_pass http://api_upstream;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
|
# WebSocket timeouts
|
||||||
|
proxy_connect_timeout 7d;
|
||||||
|
proxy_send_timeout 7d;
|
||||||
|
proxy_read_timeout 7d;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Health check endpoint
|
||||||
|
location /health {
|
||||||
|
access_log off;
|
||||||
|
return 200 'OK';
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# BMAD Web - Deploy Script
|
||||||
|
# Usage: ./scripts/deploy.sh [environment] [service]
|
||||||
|
# Examples:
|
||||||
|
# ./scripts/deploy.sh production all
|
||||||
|
# ./scripts/deploy.sh staging frontend
|
||||||
|
# ./scripts/deploy.sh production backend
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
ENVIRONMENT=${1:-production}
|
||||||
|
SERVICE=${2:-all}
|
||||||
|
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo -e "${BLUE} BMAD Web Deploy Script${NC}"
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
echo -e "Environment: ${GREEN}$ENVIRONMENT${NC}"
|
||||||
|
echo -e "Service: ${GREEN}$SERVICE${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check prerequisites
|
||||||
|
check_prerequisites() {
|
||||||
|
echo -e "${YELLOW}Checking prerequisites...${NC}"
|
||||||
|
|
||||||
|
if ! command -v node &> /dev/null; then
|
||||||
|
echo -e "${RED}Error: Node.js is not installed${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v npm &> /dev/null; then
|
||||||
|
echo -e "${RED}Error: npm is not installed${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for Vercel CLI if deploying frontend
|
||||||
|
if [[ "$SERVICE" == "frontend" || "$SERVICE" == "all" ]]; then
|
||||||
|
if ! command -v vercel &> /dev/null; then
|
||||||
|
echo -e "${YELLOW}Installing Vercel CLI...${NC}"
|
||||||
|
npm i -g vercel
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for Railway CLI if deploying backend
|
||||||
|
if [[ "$SERVICE" == "backend" || "$SERVICE" == "all" ]]; then
|
||||||
|
if ! command -v railway &> /dev/null; then
|
||||||
|
echo -e "${YELLOW}Installing Railway CLI...${NC}"
|
||||||
|
npm i -g @railway/cli
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "${GREEN}Prerequisites OK${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build packages
|
||||||
|
build_packages() {
|
||||||
|
echo -e "${YELLOW}Building shared packages...${NC}"
|
||||||
|
npm run build --workspace=@bmad/core
|
||||||
|
npm run build --workspace=@bmad/ui
|
||||||
|
echo -e "${GREEN}Packages built${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy frontend
|
||||||
|
deploy_frontend() {
|
||||||
|
echo -e "${YELLOW}Deploying frontend to Vercel...${NC}"
|
||||||
|
|
||||||
|
cd apps/web
|
||||||
|
|
||||||
|
if [[ "$ENVIRONMENT" == "production" ]]; then
|
||||||
|
vercel --prod
|
||||||
|
else
|
||||||
|
vercel
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo -e "${GREEN}Frontend deployed${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy backend
|
||||||
|
deploy_backend() {
|
||||||
|
echo -e "${YELLOW}Deploying backend to Railway...${NC}"
|
||||||
|
|
||||||
|
cd apps/api
|
||||||
|
|
||||||
|
if [[ "$ENVIRONMENT" == "production" ]]; then
|
||||||
|
railway up --detach
|
||||||
|
else
|
||||||
|
railway up --detach --environment staging
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo -e "${GREEN}Backend deployed${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run database migrations
|
||||||
|
run_migrations() {
|
||||||
|
echo -e "${YELLOW}Running database migrations...${NC}"
|
||||||
|
|
||||||
|
cd apps/api
|
||||||
|
npx prisma migrate deploy
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
echo -e "${GREEN}Migrations completed${NC}"
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
main() {
|
||||||
|
check_prerequisites
|
||||||
|
|
||||||
|
# Navigate to bmad-web directory
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR/.."
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Installing dependencies...${NC}"
|
||||||
|
npm ci
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
build_packages
|
||||||
|
|
||||||
|
case $SERVICE in
|
||||||
|
frontend)
|
||||||
|
deploy_frontend
|
||||||
|
;;
|
||||||
|
backend)
|
||||||
|
run_migrations
|
||||||
|
deploy_backend
|
||||||
|
;;
|
||||||
|
all)
|
||||||
|
deploy_frontend
|
||||||
|
run_migrations
|
||||||
|
deploy_backend
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "${RED}Unknown service: $SERVICE${NC}"
|
||||||
|
echo "Usage: ./scripts/deploy.sh [environment] [service]"
|
||||||
|
echo "Services: frontend, backend, all"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
echo -e "${GREEN} Deploy completed successfully!${NC}"
|
||||||
|
echo -e "${GREEN}========================================${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
Loading…
Reference in New Issue