| name | environment-config |
| description | Generates environment configuration (.env, Docker, CI/CD) from project requirements |
| trigger_events | ["PROJECT_SCAFFOLDED","DATABASE_SCHEMA_GENERATED","AUTH_SETUP_COMPLETE"] |
Environment Configuration Skill
Purpose
Generate complete environment configuration and infrastructure setup from project requirements.
This skill handles .env files, Docker Compose configurations, and CI/CD pipelines
for seamless development and deployment workflows.
Capabilities
| Feature | Description |
|---|
| .env Files | Template + local with auto-generated secrets |
| Docker Compose | Development, testing, and production setups |
| GitHub Actions | CI/CD pipelines for build, test, deploy |
| Secrets Generation | Secure random secrets for JWT, sessions, etc. |
Trigger Events
| Event | Action |
|---|
PROJECT_SCAFFOLDED | Generate initial .env template |
DATABASE_SCHEMA_GENERATED | Add DATABASE_URL configuration |
AUTH_SETUP_COMPLETE | Add JWT_SECRET, OAuth credentials |
Environment Files
1. Template File (.env.example)
File: .env.example
# ===========================================
# Application Configuration
# ===========================================
NODE_ENV=development
APP_URL=http://localhost:3000
PORT=3000
# ===========================================
# Database Configuration
# ===========================================
# PostgreSQL connection string
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public"
# Redis (optional - for caching/sessions)
REDIS_URL="redis://localhost:6379"
# ===========================================
# Authentication
# ===========================================
# JWT Secret (min 64 characters, generate with: openssl rand -base64 64)
JWT_SECRET=
# JWT token expiration
JWT_EXPIRES_IN=7d
# NextAuth.js (if using OAuth)
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=
# ===========================================
# OAuth Providers (optional)
# ===========================================
# Google OAuth
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# GitHub OAuth
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
# ===========================================
# External Services (if needed)
# ===========================================
# Email Service (e.g., SendGrid, Resend)
EMAIL_API_KEY=
EMAIL_FROM=noreply@example.com
# File Storage (e.g., S3, Cloudflare R2)
STORAGE_BUCKET=
STORAGE_ACCESS_KEY=
STORAGE_SECRET_KEY=
STORAGE_ENDPOINT=
# ===========================================
# Monitoring & Analytics (optional)
# ===========================================
SENTRY_DSN=
ANALYTICS_ID=
2. Local Development File (.env.local)
File: .env.local (auto-generated with real values)
# Auto-generated local development configuration
# DO NOT COMMIT THIS FILE TO VERSION CONTROL
NODE_ENV=development
APP_URL=http://localhost:3000
PORT=3000
# Database - Local PostgreSQL via Docker
DATABASE_URL="postgresql://dev:dev@localhost:5432/app?schema=public"
# Redis - Local Redis via Docker
REDIS_URL="redis://localhost:6379"
# JWT Secret (auto-generated)
JWT_SECRET=<auto-generated-64-char-base64>
JWT_EXPIRES_IN=7d
# NextAuth (auto-generated)
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=<auto-generated-32-char-base64>
3. Secret Generation
import crypto from "crypto";
function generateSecret(length: number = 64): string {
return crypto.randomBytes(length).toString("base64").slice(0, length);
}
const secrets = {
JWT_SECRET: generateSecret(64),
NEXTAUTH_SECRET: generateSecret(32),
SESSION_SECRET: generateSecret(32),
};
console.log("Generated Secrets:");
console.log("==================");
Object.entries(secrets).forEach(([key, value]) => {
console.log(`${key}=${value}`);
});
Docker Compose Configurations
1. Development Setup
File: docker-compose.yml
version: "3.8"
services:
db:
image: postgres:15-alpine
container_name: app-db
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-dev}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dev}
POSTGRES_DB: ${POSTGRES_DB:-app}
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-dev} -d ${POSTGRES_DB:-app}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
redis:
image: redis:7-alpine
container_name: app-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
networks:
- app-network
adminer:
image: adminer:latest
container_name: app-adminer
restart: unless-stopped
ports:
- "8081:8080"
depends_on:
db:
condition: service_healthy
networks:
- app-network
volumes:
postgres_data:
driver: local
redis_data:
driver: local
networks:
app-network:
driver: bridge
2. Development with Hot Reload
File: docker-compose.dev.yml
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile.dev
container_name: app-dev
restart: unless-stopped
environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://dev:dev@db:5432/app?schema=public
- REDIS_URL=redis://redis:6379
volumes:
- .:/app
- /app/node_modules
- /app/.next
ports:
- "3000:3000"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
db:
extends:
file: docker-compose.yml
service: db
redis:
extends:
file: docker-compose.yml
service: redis
networks:
app-network:
driver: bridge
volumes:
postgres_data:
redis_data:
3. Production Setup
File: docker-compose.prod.yml
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_ENV=production
container_name: app-prod
restart: always
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
- JWT_SECRET=${JWT_SECRET}
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
ports:
- "3000:3000"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
cpus: "1"
memory: 1G
reservations:
cpus: "0.5"
memory: 512M
networks:
- app-network
networks:
app-network:
driver: bridge
Dockerfiles
1. Development Dockerfile
File: Dockerfile.dev
FROM node:20-alpine
WORKDIR /app
# Install dependencies for native modules
RUN apk add --no-cache libc6-compat python3 make g++
# Copy package files
COPY package*.json ./
COPY prisma ./prisma/
# Install dependencies
RUN npm ci
# Generate Prisma client
RUN npx prisma generate
# Copy source files (will be overwritten by volume mount)
COPY . .
# Expose port
EXPOSE 3000
# Start development server with hot reload
CMD ["npm", "run", "dev"]
2. Production Dockerfile
File: Dockerfile
# ============================================
# Stage 1: Dependencies
# ============================================
FROM node:20-alpine AS deps
WORKDIR /app
RUN apk add --no-cache libc6-compat
COPY package*.json ./
COPY prisma ./prisma/
RUN npm ci --only=production && \
npx prisma generate
# ============================================
# Stage 2: Builder
# ============================================
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV production
RUN npm run build
# ============================================
# Stage 3: Runner
# ============================================
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 /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/prisma ./prisma
COPY --from=deps /app/node_modules/.prisma ./node_modules/.prisma
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
GitHub Actions CI/CD
1. CI Pipeline
File: .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: "20"
DATABASE_URL: "postgresql://test:test@localhost:5432/test?schema=public"
jobs:
lint:
name: Lint & Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run ESLint
run: npm run lint
- name: Run TypeScript check
run: npm run type-check
test:
name: Unit Tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Generate Prisma client
run: npx prisma generate
- name: Run database migrations
run: npx prisma migrate deploy
- name: Run tests
run: npm run test:ci
- name: Upload coverage
uses: codecov/codecov-action@v3
if: always()
with:
files: ./coverage/lcov.info
build:
name: Build
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Generate Prisma client
run: npx prisma generate
- name: Build application
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build
path: .next/
retention-days: 7
2. Deploy Pipeline
File: .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-push:
name: Build & Push
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v4
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=
type=ref,event=branch
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: build-push
environment: production
steps:
- name: Deploy to server
uses: appleboy/ssh-action@v1.0.0
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_KEY }}
script: |
cd /opt/app
docker compose pull
docker compose up -d --remove-orphans
docker system prune -f
- name: Health check
run: |
sleep 30
curl -f ${{ secrets.PRODUCTION_URL }}/api/health || exit 1
Scripts
1. Setup Script
File: scripts/setup.sh
#!/bin/bash
set -e
echo "🚀 Setting up development environment..."
command -v docker >/dev/null 2>&1 || { echo "Docker is required but not installed."; exit 1; }
command -v node >/dev/null 2>&1 || { echo "Node.js is required but not installed."; exit 1; }
if [ ! -f .env.local ]; then
echo "📝 Creating .env.local from template..."
cp .env.example .env.local
JWT_SECRET=$(openssl rand -base64 64 | tr -d '\n')
NEXTAUTH_SECRET=$(openssl rand -base64 32 | tr -d '\n')
if [[ "$OSTYPE" == "darwin"* ]]; then
sed -i '' "s|^JWT_SECRET=.*|JWT_SECRET=$JWT_SECRET|" .env.local
sed -i '' "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$NEXTAUTH_SECRET|" .env.local
else
sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$JWT_SECRET|" .env.local
sed -i "s|^NEXTAUTH_SECRET=.*|NEXTAUTH_SECRET=$NEXTAUTH_SECRET|" .env.local
fi
echo "✅ Generated secrets in .env.local"
fi
echo "🐳 Starting Docker services..."
docker compose up -d
echo "⏳ Waiting for database..."
sleep 5
echo "📦 Installing dependencies..."
npm ci
echo "🔧 Generating Prisma client..."
npx prisma generate
echo "🗃️ Running database migrations..."
npx prisma migrate dev
if [ -f prisma/seed.ts ]; then
echo "🌱 Seeding database..."
npx prisma db seed
fi
echo ""
echo "✅ Setup complete!"
echo ""
echo "To start the development server:"
echo " npm run dev"
echo ""
echo "Database admin UI available at:"
echo " http://localhost:8081"
Anti-Mock Policy
NIEMALS generieren:
IMMER generieren:
Output Files
output/
├── .env.example # Template mit Dokumentation
├── .env.local # Lokale Werte (auto-generiert)
├── docker-compose.yml # Base services (DB, Redis)
├── docker-compose.dev.yml # Development mit Hot-Reload
├── docker-compose.prod.yml # Production Setup
├── Dockerfile # Production multi-stage
├── Dockerfile.dev # Development
├── .dockerignore # Docker ignore patterns
├── .github/
│ └── workflows/
│ ├── ci.yml # Lint, Test, Build
│ └── deploy.yml # Docker Build + Deploy
└── scripts/
├── setup.sh # Initial setup
└── generate-secrets.ts # Secret generation
Dependencies
{
"scripts": {
"setup": "bash scripts/setup.sh",
"docker:up": "docker compose up -d",
"docker:down": "docker compose down",
"docker:logs": "docker compose logs -f"
}
}