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
35 changes: 35 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Server Configuration
NODE_ENV=production
PORT=5000

# Database Configuration
DATABASE_URL="postgresql://eraser_user:eraser_pass@localhost:5432/eraser_db?schema=public"

# JWT Configuration
JWT_SECRET=your_super_secret_jwt_key_change_this_in_production_min_32_chars
JWT_EXPIRES_IN=7d

# Frontend URLs (CORS)
FRONTEND_URL=http://localhost:5173
FRONTEND_URL_PROD=https://your-production-domain.com

# Redis (Optional - for horizontal scaling)
REDIS_URL=redis://localhost:6379

# Logging
LOG_LEVEL=info

# Rate Limiting
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100

# Application Settings
MAX_BOARD_SIZE_MB=50
MAX_CONCURRENT_USERS_PER_BOARD=50
SAVE_DEBOUNCE_MS=2000

# Email Configuration (Optional)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
17 changes: 17 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
env: {
node: true,
es2021: true,
jest: true,
},
extends: 'eslint:recommended',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'no-console': 'warn',
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'prefer-const': 'error',
},
};
68 changes: 68 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: CI/CD Pipeline

on:
push:
branches: [main, develop]
pull_request:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:17-alpine
env:
POSTGRES_USER: test_user
POSTGRES_PASSWORD: test_pass
POSTGRES_DB: test_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- uses: actions/checkout@v3

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

- name: Install dependencies
run: npm ci

- name: Generate Prisma Client
run: npx prisma generate

- name: Run migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: postgresql://test_user:test_pass@localhost:5432/test_db

- name: Run tests
run: npm test
env:
DATABASE_URL: postgresql://test_user:test_pass@localhost:5432/test_db
JWT_SECRET: test_secret_key_min_32_characters_long

- name: Lint code
run: npm run lint

deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'

steps:
- uses: actions/checkout@v3

- name: Deploy to production
run: |
echo "Deploy to your server here"
# Add your deployment script
31 changes: 0 additions & 31 deletions .github/workflows/node.js.yml

This file was deleted.

44 changes: 41 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
node_modules
# Keep environment variables out of version control
# Dependencies
node_modules/
package-lock.json
yarn.lock
pnpm-lock.yaml

# Environment
.env
.env.local
.env.*.local

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Database
prisma/dev.db
prisma/dev.db-journal

# OS
.DS_Store
Thumbs.db

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# Testing
coverage/
.nyc_output/

# Build
dist/
build/

/generated/prisma
# PM2
.pm2/
8 changes: 8 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"arrowParens": "always"
}
33 changes: 33 additions & 0 deletions DockerFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
FROM node:18-alpine3.18

# Update packages and Install OpenSSL for Prisma
RUN apk update && apk upgrade --no-cache \
&& apk add --no-cache openssl

WORKDIR /app

# Copy package files
COPY package*.json ./
COPY prisma ./prisma/

# Install dependencies
RUN npm ci --only=production

# Generate Prisma Client
RUN npx prisma generate

# Copy source code
COPY src ./src

# Create logs directory
RUN mkdir -p logs

# Expose port
EXPOSE 5000

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
CMD node -e "require('http').get('http://localhost:5000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"

# Start application
CMD ["node", "src/index.js"]
67 changes: 67 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
version: '3.8'

services:
postgres:
image: postgres:17-alpine
container_name: eraser-postgres
environment:
POSTGRES_USER: eraser_user
POSTGRES_PASSWORD: eraser_pass
POSTGRES_DB: eraser_db
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U eraser_user"]
interval: 10s
timeout: 5s
retries: 5
networks:
- eraser-network

redis:
image: redis:7-alpine
container_name: eraser-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
networks:
- eraser-network

app:
build: .
container_name: eraser-backend
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 5000
DATABASE_URL: postgresql://eraser_user:eraser_pass@postgres:5432/eraser_db?schema=public
REDIS_URL: redis://redis:6379
env_file:
- .env
ports:
- "5000:5000"
volumes:
- ./logs:/app/logs
restart: unless-stopped
networks:
- eraser-network

volumes:
postgres_data:
redis_data:

networks:
eraser-network:
driver: bridge
27 changes: 27 additions & 0 deletions ecosystem.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module.exports = {
apps: [
{
name: 'eraser-backend',
script: './src/index.js',
instances: 'max', // Use all CPU cores
exec_mode: 'cluster',
watch: false, // Disable in production
max_memory_restart: '1G',
env_production: {
NODE_ENV: 'production',
PORT: 5000,
},
env_development: {
NODE_ENV: 'development',
PORT: 5000,
},
error_file: './logs/pm2-error.log',
out_file: './logs/pm2-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
autorestart: true,
max_restarts: 10,
min_uptime: '10s',
},
],
};
Loading
Loading