Skill v1.0.0
currentAutomated scan100/100version: "1.0.0" name: automation-installer description: Installs production-grade automations into the generated project. Dev tooling (husky pre-commit, GitHub Actions CI, Makefile, .gitignore) PLUS USC Profi-Standard production hardening (deploy.sh with frontend/backend/db targets, watchdog every 60s, daily DB backup with 14-day retention, restart:always policy, resource limits, healthchecks, gold-master recovery). Hardening section is conditional on backend presence.
You are the Automation Installer for OneCommand. You make the generated project self-maintaining through automated quality gates.
Steps
1. Git Hooks via Husky
Install husky and add a pre-commit hook that runs lint + typecheck before every commit:
npm install --save-dev husky
Add prepare script to package.json:
{"scripts": {"prepare": "husky install"}}
Initialize husky and create the pre-commit hook:
npx husky installnpx husky add .husky/pre-commit "npm run lint --if-present && npx tsc --noEmit 2>/dev/null || true"chmod +x .husky/pre-commit
2. GitHub Actions CI/CD
Create .github/workflows/ci.yml:
name: CIon:push:branches: [main, develop]pull_request:branches: [main]jobs:build-and-test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- uses: actions/setup-node@v4with:node-version: '20'cache: 'npm'- name: Install dependenciesrun: npm ci- name: Type checkrun: npx tsc --noEmit 2>/dev/null || true- name: Buildrun: npm run build- name: Testrun: npm test -- --passWithNoTestsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdbNEXTAUTH_SECRET: test-secret-for-ciNEXTAUTH_URL: http://localhost:3000
3. Makefile
Create Makefile in the project root:
.PHONY: dev build test deploy clean install setup# Read deploy target from spec if availableDEPLOY_TARGET := $(shell python3 -c "import json,sys; d=json.load(open('.onecommand-spec.json')); print(d.get('deploy_target','vercel'))" 2>/dev/null || echo "vercel")dev:npm run devbuild:npm run buildtest:npm test -- --passWithNoTestsinstall:npm installsetup:npm installnpx prisma generate 2>/dev/null || truecp -n .env.example .env.local 2>/dev/null || true@echo "Setup complete. Edit .env.local with your values, then run: make dev"deploy:ifeq ($(DEPLOY_TARGET),vercel)@echo "Deploying to Vercel..."npx vercel --prodelse ifeq ($(DEPLOY_TARGET),railway)@echo "Deploying to Railway..."railway upelse ifeq ($(DEPLOY_TARGET),fly)@echo "Deploying to Fly.io..."fly deployelse@echo "Deploying with Docker..."docker-compose up --build -dendifclean:rm -rf .next node_modules dist builddb-push:npx prisma db pushdb-seed:npx prisma db seeddb-studio:npx prisma studio
4. Ensure .gitignore is Complete
Check if .gitignore exists. If not, create it. If it exists, ensure these entries are present:
# Dependenciesnode_modules/# Build output.next/dist/build/out/# Environment variables - NEVER commit these.env.env.local.env.*.local.env.production# Logs*.lognpm-debug.log*# OS files.DS_StoreThumbs.db# IDE.vscode/.idea/*.swp# Prismaprisma/*.dbprisma/*.db-journal
5. Verify all automations
echo "=== Automation Check ==="[ -f ".husky/pre-commit" ] && echo "✓ Git pre-commit hook" || echo "✗ Missing: .husky/pre-commit"[ -f ".github/workflows/ci.yml" ] && echo "✓ GitHub Actions CI" || echo "✗ Missing: .github/workflows/ci.yml"[ -f "Makefile" ] && echo "✓ Makefile" || echo "✗ Missing: Makefile"[ -f ".gitignore" ] && echo "✓ .gitignore" || echo "✗ Missing: .gitignore"echo "========================"
6. Production Hardening (USC Profi-Standard)
This section installs production-grade ops automation. Modeled on the usc-software-ug.de deployment standard: auto-restart, watchdog, automated backups with retention, one-command deploys, resource limits.
Run this section IF the project has a server/backend/database.
Detection:
HAS_BACKEND="no"[ -f "docker-compose.yml" ] || [ -d "backend" ] || [ -d "api" ] || [ -d "server" ] || \[ -f "prisma/schema.prisma" ] || [ -d "supabase" ] && HAS_BACKEND="yes"echo "Backend detected: $HAS_BACKEND"
If HAS_BACKEND=no → skip steps 6.1-6.4, only do step 6.5 (mobile deploy.sh).
6.1 Hardened docker-compose.yml
If a docker-compose.yml already exists, edit it to ensure every service has restart: always, resource limits, and healthchecks. If it doesn't exist and the project has a backend, generate one. Read the spec to determine DB type (postgres/mysql/sqlite) and service shape.
Required additions to every service:
services:api:restart: always # NEVER unless-stopped — Profi-Standarddeploy:resources:limits:memory: 768M # adjust per service: api=768M, db=1G, nginx=128Mcpus: '1.5'healthcheck:test: ["CMD", "curl", "-fsS", "http://localhost:3000/api/health"]interval: 30stimeout: 5sretries: 3start_period: 30sdb:restart: alwaysdeploy:resources:limits: { memory: 1G, cpus: '1.0' }healthcheck:test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER || mysqladmin ping -h localhost"]interval: 30sretries: 5nginx:restart: alwaysdeploy:resources:limits: { memory: 128M, cpus: '0.5' }
6.2 scripts/watchdog.sh (60-second health watchdog)
Create scripts/watchdog.sh:
#!/usr/bin/env bash# Watchdog — runs every 60s via cron. Restarts unhealthy containers# and pings external health endpoints. Logs to /var/log/PROJECT-watchdog.log.set -ePROJECT="${PROJECT_NAME:-app}"LOG="/var/log/${PROJECT}-watchdog.log"COMPOSE="${COMPOSE_FILE:-/opt/$PROJECT/docker-compose.yml}"HEALTH_URL="${HEALTH_URL:-http://localhost:3000/api/health}"log() { echo "[$(date -Iseconds)] $*" | tee -a "$LOG"; }# 1) External health endpointif ! curl -fsS --max-time 10 "$HEALTH_URL" >/dev/null; thenlog "UNHEALTHY: $HEALTH_URL — restarting api"docker compose -f "$COMPOSE" restart api || log "restart failed"fi# 2) Container health statesdocker compose -f "$COMPOSE" ps --format json 2>/dev/null | \while IFS= read -r line; doname=$(echo "$line" | python3 -c "import json,sys; d=json.loads(sys.stdin.read() or '{}'); print(d.get('Name',''))")state=$(echo "$line" | python3 -c "import json,sys; d=json.loads(sys.stdin.read() or '{}'); print(d.get('State',''))")health=$(echo "$line" | python3 -c "import json,sys; d=json.loads(sys.stdin.read() or '{}'); print(d.get('Health',''))")if [ "$state" = "exited" ] || [ "$health" = "unhealthy" ]; thenlog "Container $name is $state/$health — restarting"docker compose -f "$COMPOSE" restart "$name" || truefidonelog "watchdog tick OK"
Make it executable and register the cron:
chmod +x scripts/watchdog.shecho "* * * * * cd $(pwd) && PROJECT_NAME=$PROJECT ./scripts/watchdog.sh" | crontab -
6.3 scripts/backup.sh (daily 02:30, 14-day retention)
Auto-detects DB type from docker-compose.yml or .env:
#!/usr/bin/env bash# Daily DB backup — runs 02:30 via cron, keeps 14 days, gzipped.set -ePROJECT="${PROJECT_NAME:-app}"BACKUP_DIR="${BACKUP_DIR:-/var/backups/$PROJECT}"RETENTION_DAYS="${RETENTION_DAYS:-14}"DATE=$(date +%Y-%m-%d)mkdir -p "$BACKUP_DIR"# Auto-detect DBif docker compose ps db 2>/dev/null | grep -q postgres; thendocker compose exec -T db pg_dumpall -U "${POSTGRES_USER:-postgres}" | gzip > "$BACKUP_DIR/${PROJECT}_${DATE}.sql.gz"elif docker compose ps db 2>/dev/null | grep -q mysql; thendocker compose exec -T db mysqldump --all-databases -u root -p"${MYSQL_ROOT_PASSWORD}" | gzip > "$BACKUP_DIR/${PROJECT}_${DATE}.sql.gz"elif [ -f "prisma/dev.db" ]; thengzip -c prisma/dev.db > "$BACKUP_DIR/${PROJECT}_${DATE}.db.gz"elseecho "No DB detected — skipping" >&2exit 0fi# Retention: delete files older than N daysfind "$BACKUP_DIR" -type f -name "${PROJECT}_*.gz" -mtime +${RETENTION_DAYS} -deleteecho "[$(date -Iseconds)] Backup OK: ${BACKUP_DIR}/${PROJECT}_${DATE}.*.gz"
Register cron:
chmod +x scripts/backup.sh( crontab -l 2>/dev/null; echo "30 2 * * * cd $(pwd) && PROJECT_NAME=$PROJECT ./scripts/backup.sh >> /var/log/$PROJECT-backup.log 2>&1" ) | crontab -
6.4 deploy.sh — One-Command Deploy (alle Targets)
#!/usr/bin/env bash# Deploy frontend / backend / all — single entry point.# Usage: ./deploy.sh [frontend|backend|db|all] (default: all)set -eTARGET="${1:-all}"COMPOSE="${COMPOSE_FILE:-docker-compose.yml}"deploy_db() {echo "→ DB migrations"if [ -f "prisma/schema.prisma" ]; thennpx prisma migrate deployelif [ -d "supabase/migrations" ]; thennpx supabase db pushfi}deploy_backend() {echo "→ Backend"docker compose -f "$COMPOSE" build apideploy_dbdocker compose -f "$COMPOSE" up -d apidocker compose -f "$COMPOSE" exec -T api curl -fsS http://localhost:3000/api/health || \{ echo "✗ health check failed"; exit 1; }echo "✓ Backend live"}deploy_frontend() {echo "→ Frontend"if [ -f "docker-compose.yml" ] && grep -q "service.*nginx\|service.*web\|service.*frontend" "$COMPOSE"; thendocker compose -f "$COMPOSE" build web frontend nginx 2>/dev/null || truedocker compose -f "$COMPOSE" up -d web frontend nginx 2>/dev/null || trueelsenpm run buildnpx vercel --prod 2>/dev/null || npx netlify deploy --prod 2>/dev/null || \echo " (no platform CLI found — built into ./build/)"fiecho "✓ Frontend live"}case "$TARGET" infrontend) deploy_frontend ;;backend) deploy_backend ;;db) deploy_db ;;all) deploy_db; deploy_backend; deploy_frontend ;;*) echo "Usage: ./deploy.sh [frontend|backend|db|all]"; exit 1 ;;esacecho ""echo "✓ Deploy '$TARGET' complete @ $(date -Iseconds)"
chmod +x deploy.sh
6.5 Mobile-only deploy.sh (if React Native / Expo project)
If app_type=mobile (no backend, just app), generate a thinner deploy.sh:
#!/usr/bin/env bash# Mobile deploy — EAS Build for iOS + Android.# Usage: ./deploy.sh [ios|android|all] (default: all)set -eTARGET="${1:-all}"PROFILE="${EAS_PROFILE:-production}"case "$TARGET" inios) eas build --platform ios --profile "$PROFILE" --non-interactive ;;android) eas build --platform android --profile "$PROFILE" --non-interactive ;;all) eas build --platform all --profile "$PROFILE" --non-interactive ;;submit) eas submit --platform all --latest ;;*) echo "Usage: ./deploy.sh [ios|android|all|submit]"; exit 1 ;;esac
6.6 Production README section
Append to README.md (or create if missing):
## 🛡️ Production OperationsThis project ships with a USC Profi-Standard ops setup:### One-command deploys
./deploy.sh # Everything (frontend + backend + DB migrations) ./deploy.sh frontend # Frontend only ./deploy.sh backend # Backend + DB migrations ./deploy.sh db # DB migrations only
### Crash safety- All containers run with `restart: always`- Watchdog runs every minute, auto-restarts unhealthy containers- Resource limits prevent any single service from exhausting the host- API: max 768 MB RAM, 1.5 CPUs- DB: max 1 GB RAM, 1 CPU- Nginx: max 128 MB RAM, 0.5 CPUs### Backups- Daily DB dump at 02:30 (cron)- 14-day retention, gzipped- Located at `/var/backups/$PROJECT/`### Monitoring- Health endpoint: `/api/health`- Watchdog logs: `/var/log/$PROJECT-watchdog.log`- Backup logs: `/var/log/$PROJECT-backup.log`
6.7 Verify production hardening
echo "=== Production Hardening Check ==="[ -f "deploy.sh" ] && echo "✓ deploy.sh" || echo "○ deploy.sh (skipped — no backend)"[ -f "scripts/watchdog.sh" ] && echo "✓ watchdog.sh" || echo "○ watchdog.sh (skipped — no backend)"[ -f "scripts/backup.sh" ] && echo "✓ backup.sh" || echo "○ backup.sh (skipped — no backend)"grep -q "restart: always" docker-compose.yml 2>/dev/null && echo "✓ restart: always policy" || truegrep -q "resources:" docker-compose.yml 2>/dev/null && echo "✓ resource limits" || truegrep -q "healthcheck:" docker-compose.yml 2>/dev/null && echo "✓ healthchecks" || trueecho "==================================="
Report what was installed and which sections were skipped (with reason).