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
117 changes: 117 additions & 0 deletions .github/workflows/backend-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
name: Backend Deployment

on:
push:
branches:
- main
paths:
- 'backend/**'
- '.github/workflows/backend-deploy.yml'
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest pytest-cov black isort
pip install -r requirements.txt

- name: Run tests
env:
TESTING: "True"
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/test_db"
DATABASE_TEST_URL: "postgresql://postgres:postgres@localhost:5432/test_db"
SECRET_KEY: "test-secret-key-for-ci-environment"
AUTH0_DOMAIN: "example.auth0.com"
AUTH0_CLIENT_ID: "test-client-id"
AUTH0_CLIENT_SECRET: "test-client-secret"
AUTH0_AUDIENCE: "https://api.example.com"
OPENAI_API_KEY: "sk-test-key"
run: pytest --cov=app --cov-report=xml

- name: Generate deployment package
run: |
mkdir -p deployment_package
cp -r app deployment_package/
cp -r scripts deployment_package/
cp requirements.txt deployment_package/
cp Procfile deployment_package/ || echo "No Procfile found, creating one"
if [ ! -f deployment_package/Procfile ]; then
echo "web: uvicorn app.main:app --host 0.0.0.0 --port \$PORT" > deployment_package/Procfile
fi
cd deployment_package && zip -r ../deployment_package.zip .

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Deploy to Elastic Beanstalk
uses: einaregilsson/beanstalk-deploy@v21
with:
aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
application_name: ${{ secrets.EB_APPLICATION_NAME }}
environment_name: ${{ secrets.EB_ENVIRONMENT_NAME }}
version_label: "ver-${{ github.sha }}"
region: ${{ secrets.AWS_REGION }}
deployment_package: deployment_package.zip
wait_for_environment_recovery: 300

- name: Send deployment notification
if: always()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "${{ job.status == 'success' && '✅ Backend deployed successfully' || '❌ Backend deployment failed' }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "${{ job.status == 'success' && '✅ Backend deployed successfully to Elastic Beanstalk' || '❌ Backend deployment failed' }}"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Environment:* ${{ secrets.EB_ENVIRONMENT_NAME }}"
},
{
"type": "mrkdwn",
"text": "*Version:* ver-${{ github.sha }}"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Commit:* <${{ github.event.repository.html_url }}/commit/${{ github.sha }}|${{ github.sha }}>"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
106 changes: 106 additions & 0 deletions .github/workflows/frontend-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
name: Frontend Deployment

on:
push:
branches:
- main
paths:
- 'frontend/**'
- '.github/workflows/frontend-deploy.yml'
workflow_dispatch:

jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend

steps:
- uses: actions/checkout@v4

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

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test -- --coverage

- name: Create production build
env:
CI: "true"
VITE_API_URL: ${{ secrets.VITE_API_URL }}
VITE_AUTH0_DOMAIN: ${{ secrets.VITE_AUTH0_DOMAIN }}
VITE_AUTH0_CLIENT_ID: ${{ secrets.VITE_AUTH0_CLIENT_ID }}
VITE_AUTH0_AUDIENCE: ${{ secrets.VITE_AUTH0_AUDIENCE }}
VITE_DEV_MODE: "false"
run: npm run build

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Deploy to S3
run: |
aws s3 sync dist/ s3://${{ secrets.S3_BUCKET_NAME }}/ --delete

- name: Invalidate CloudFront cache
run: |
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"

- name: Send deployment notification
if: always()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "${{ job.status == 'success' && '✅ Frontend deployed successfully' || '❌ Frontend deployment failed' }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "${{ job.status == 'success' && '✅ Frontend deployed successfully to S3 and CloudFront' || '❌ Frontend deployment failed' }}"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*S3 Bucket:* ${{ secrets.S3_BUCKET_NAME }}"
},
{
"type": "mrkdwn",
"text": "*CloudFront:* ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }}"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Commit:* <${{ github.event.repository.html_url }}/commit/${{ github.sha }}|${{ github.sha }}>"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Live URL:* https://${{ secrets.SITE_DOMAIN }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
147 changes: 147 additions & 0 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Deployment Guide

This document provides detailed instructions for setting up and configuring the deployment pipeline for the Toban Contribution Viewer project.

## Infrastructure Setup

### Backend: AWS Elastic Beanstalk

1. **Create an Elastic Beanstalk Application:**
```bash
aws elasticbeanstalk create-application --application-name toban-contribution-viewer
```

2. **Create an Elastic Beanstalk Environment:**
```bash
aws elasticbeanstalk create-environment \
--application-name toban-contribution-viewer \
--environment-name toban-contribution-viewer-prod \
--solution-stack-name "64bit Amazon Linux 2023 v4.0.6 running Python 3.12" \
--option-settings file://backend/eb-config.json
```

3. **Configure Environment Variables:**
Set the following environment variables in the Elastic Beanstalk environment:
- `DATABASE_URL`: Your production PostgreSQL connection string
- `SECRET_KEY`: A secure random string for production
- `AUTH0_DOMAIN`: Your Auth0 domain
- `AUTH0_CLIENT_ID`: Your Auth0 client ID
- `AUTH0_CLIENT_SECRET`: Your Auth0 client secret
- `AUTH0_AUDIENCE`: Your Auth0 API audience
- `OPENAI_API_KEY`: Your OpenAI API key

4. **Set Up Database:**
- Create an RDS PostgreSQL instance
- Configure security groups to allow access from your Elastic Beanstalk environment
- Create the initial database schema

### Frontend: AWS S3 and CloudFront

1. **Create an S3 Bucket:**
```bash
aws s3 mb s3://toban-contribution-viewer-frontend --region us-east-1
```

2. **Configure the S3 Bucket for Static Website Hosting:**
```bash
aws s3 website s3://toban-contribution-viewer-frontend \
--index-document index.html \
--error-document index.html
```

3. **Set Bucket Policy for Public Access:**
Create a file named `bucket-policy.json` with the following content:
```json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::toban-contribution-viewer-frontend/*"
}
]
}
```
Apply the policy:
```bash
aws s3api put-bucket-policy \
--bucket toban-contribution-viewer-frontend \
--policy file://bucket-policy.json
```

4. **Create a CloudFront Distribution:**
```bash
aws cloudfront create-distribution \
--origin-domain-name toban-contribution-viewer-frontend.s3.amazonaws.com \
--default-root-object index.html
```

5. **Configure Custom Domain (Optional):**
- Create a certificate using AWS Certificate Manager
- Add the domain to your CloudFront distribution
- Configure DNS settings to point to your CloudFront distribution

## GitHub Actions Setup

### Creating Required Secrets

Add the following secrets to your GitHub repository:

1. AWS credentials:
- `AWS_ACCESS_KEY_ID`: Your AWS access key
- `AWS_SECRET_ACCESS_KEY`: Your AWS secret key
- `AWS_REGION`: The AWS region (e.g., us-east-1)

2. Elastic Beanstalk configuration:
- `EB_APPLICATION_NAME`: Your Elastic Beanstalk application name (e.g., toban-contribution-viewer)
- `EB_ENVIRONMENT_NAME`: Your Elastic Beanstalk environment name (e.g., toban-contribution-viewer-prod)

3. S3 and CloudFront configuration:
- `S3_BUCKET_NAME`: Your S3 bucket name (e.g., toban-contribution-viewer-frontend)
- `CLOUDFRONT_DISTRIBUTION_ID`: Your CloudFront distribution ID
- `SITE_DOMAIN`: Your site domain (e.g., app.yoursite.com)

4. Environment-specific variables:
- All the required backend and frontend environment variables for production

5. Slack notifications (optional):
- `SLACK_WEBHOOK_URL`: Your Slack webhook URL for deployment notifications

### Testing the Deployment

1. Push a change to the main branch to trigger the deployment workflow
2. Monitor the GitHub Actions workflow run
3. Verify the deployment was successful by accessing your application

## Deployment Environments

### Production

The production environment is automatically deployed when changes are pushed to the main branch. You can also manually trigger a deployment through the GitHub Actions interface.

### Staging (Optional)

To set up a staging environment:

1. Create additional Elastic Beanstalk environment and S3 bucket for staging
2. Create a new GitHub workflow file specifically for staging deployment
3. Configure the workflow to deploy to the staging environment when changes are pushed to a staging branch

## Rollback Procedures

### Backend Rollback

1. Open the Elastic Beanstalk console
2. Navigate to your environment
3. Select the "Application versions" tab
4. Select the previous working version
5. Click "Deploy" to roll back to that version

### Frontend Rollback

1. Navigate to your S3 bucket
2. Restore a previous version using S3 versioning
3. Invalidate the CloudFront cache to serve the restored version
Loading