---
name: easypanel-validate
description: Validação pré-deploy de projectos EasyPanel com health checks, verificação de serviços e auto-fix opcional via API oficial.
---

# EasyPanel Validate

Validação pré-deploy de projectos EasyPanel com auto-fix opcional.

## Quando Usar

- Antes de deploy (pre-flight check)
- Após criar novo projecto
- Para auditar projecto existente
- Quality gate antes de commit
- CI/CD validation step

## Sintaxe

```bash
/easypanel-validate [--fix] [--strict]
```

## Exemplos

```bash
# Validação sem correcções
/easypanel-validate

# Validação com auto-fix (cria ficheiros em falta)
/easypanel-validate --fix

# Modo strict (fail on warnings)
/easypanel-validate --strict
```

## Validation Checks (10 categorias)

### 1. Check Dockerfile

```bash
# Lint com hadolint (Docker best practices)
hadolint Dockerfile
```

**Checks:**
- ✅ Multi-stage build (>= 2 stages)
- ✅ FROM com versão específica (not :latest)
- ✅ HEALTHCHECK presente
- ✅ USER non-root
- ✅ EXPOSE port
- ⚠️  Warnings: npm install (usar npm ci), COPY . antes package.json

**Auto-fix (--fix):**
- Adicionar USER nodejs se ausente
- Adicionar HEALTHCHECK se ausente
- Sugerir multi-stage (não altera automaticamente)

### 2. Check .dockerignore

**Checks:**
- ✅ Existe
- ✅ Espelha .gitignore (node_modules, dist, .env)
- ❌ Se não existe → --fix: criar automaticamente

**Auto-fix (--fix):**
```
node_modules
dist
build
.env
.env.local
*.log
.git
.DS_Store
```

### 3. Check docker-compose.yml

**Checks:**
- ✅ Traefik labels presentes
- ✅ router.rule com domain
- ✅ service.loadbalancer.server.port match Dockerfile EXPOSE
- ✅ healthcheck.path configurado (/health)
- ⚠️  Warnings: certresolver não é letsencrypt, restart policy não definida

**Auto-fix (--fix):**
- Adicionar restart: unless-stopped
- Corrigir sintaxe de labels Traefik

### 4. Check package.json (Node.js)

**Checks:**
- ✅ Scripts: build, start, lint, test
- ✅ Dependencies: express/fastify (API framework)
- ⚠️  devDependencies em dependencies (bloat)

### 5. Check Health Endpoint

**Checks:**
- ✅ Ficheiro existe (src/routes/health.ts ou similar)
- ✅ GET /health implementado
- ❌ Se não existe → --fix: criar template

**Template Health Endpoint (Node.js/Express):**
```typescript
import { Router } from 'express'

const router = Router()

router.get('/health', (req, res) => {
  res.status(200).json({
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime()
  })
})

export default router
```

### 6. Check .gitignore

**Checks:**
- ✅ node_modules
- ✅ dist/build
- ✅ .env (não .env.example)
- ✅ logs/

### 7. Check .env.example

**Checks:**
- ✅ Existe (template para .env)
- ✅ Todas vars documentadas
- ⚠️  Valores default sensíveis (passwords)

### 8. Check CI/CD

**Checks:**
- ✅ .gitea/workflows/deploy.yml existe
- ✅ Webhook URL configurado (secret)
- ⚠️  Tests não rodando (npm test ausente)

**Auto-fix (--fix):**
- Criar .gitea/workflows/deploy.yml usando template

### 9. Test Local Build

```bash
docker build --no-cache -t test:validate .
```

**Checks:**
- Build completa sem erros
- Image size < 200MB (Node.js)
- Image size > 200MB (optimizar multi-stage)

### 10. Validar Serviço via API (se já deployed)

```bash
# Obter token
TOKEN=$(cat /etc/easypanel/.api-token)

# Verificar estado do serviço existente
curl -s "http://localhost:3000/api/trpc/services.app.inspectService?input=$(echo -n '{"json":{"projectName":"PROJECT","serviceName":"SERVICE"}}' | jq -sRr @uri)" \
  -H "Authorization: Bearer $TOKEN" | jq '.result.data.json'

# Verificar estatisticas de recursos
curl -s "http://localhost:3000/api/trpc/monitor.getSystemStats" \
  -H "Authorization: Bearer $TOKEN"
```

### 11. Output Report

**Score: X/10**
- Cada categoria = 1 ponto
- Critical issues = 0 pontos
- Warnings = 0.5 pontos

## Output Format

```
🔍 EasyPanel Deploy Validation

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 SCORE: X/10 (EXCELLENT | GOOD | FAIR | POOR)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✅ PASSED (X)
   1. Dockerfile: Multi-stage build
   2. docker-compose.yml: Traefik configured
   ...

⚠️  WARNINGS (X)
   1. Dockerfile: Use 'npm ci' instead of 'npm install'
   2. docker-compose.yml: Missing restart policy
   ...

❌ CRITICAL (X)
   1. .dockerignore: FILE MISSING
      → Impact: Build includes unnecessary files
      → Fix: Create .dockerignore

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔧 AUTO-FIXES (--fix flag detected)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✅ Created .dockerignore
✅ Updated docker-compose.yml: Added restart policy
✅ Dockerfile: Changed npm install → npm ci

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 RECOMMENDATIONS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1. Add .gitea/workflows/deploy.yml for CI/CD
2. Implement integration tests
3. Consider Prometheus metrics endpoint (/metrics)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ READY TO DEPLOY (score >= 7/10)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Next: /easypanel-deploy or git push origin main
```

## Score Interpretation

| Score | Status | Action |
|-------|--------|--------|
| 9-10 | EXCELLENT | Deploy com confiança |
| 7-8 | GOOD | Deploy OK, resolver warnings depois |
| 5-6 | FAIR | Resolver critical issues antes de deploy |
| 0-4 | POOR | BLOCKER - Não deploy até corrigir |

## Strict Mode (--strict)

Se `--strict`:
- Warnings são tratados como CRITICAL
- Score mínimo para pass: 9/10
- Exit code 1 se score < 9

Uso em CI/CD:
```yaml
- name: Validate
  run: /easypanel-validate --strict
```

## Auto-Fix Capabilities

| Issue | Auto-Fix? | Action |
|-------|-----------|--------|
| .dockerignore missing | ✅ Yes | Create from template |
| .gitignore incomplete | ✅ Yes | Append missing entries |
| docker-compose restart policy | ✅ Yes | Add unless-stopped |
| Health endpoint missing | ✅ Yes | Create template file |
| Dockerfile npm install | ✅ Yes | Replace with npm ci |
| Multi-stage missing | ❌ No | Recommend only |
| Port mismatch | ❌ No | Report only |

## API Endpoints Usados

Ver skill `/easypanel-api` para documentação completa.

| Acção | Endpoint | Verificado |
|-------|----------|:----------:|
| Inspeccionar serviço | `GET services.app.inspectService` | Sim |
| Stats sistema | `GET monitor.getSystemStats` | Sim |
| Listar projectos | `GET projects.listProjects` | Sim |
| IP servidor | `GET settings.getServerIp` | Sim |

**Endpoints que NAO existem:** `monitor.getStats` (usar `monitor.getSystemStats`), `settings.getSystemInfo` (usar `settings.getServerIp`).

## Tools Necessários

```bash
# Docker para build test
docker build --no-cache -t test .

# hadolint para Dockerfile lint (opcional)
hadolint Dockerfile
```

## Integration com CI/CD

```yaml
# .gitea/workflows/deploy.yml
steps:
  - name: Validate
    run: /easypanel-validate --strict

  - name: Deploy
    if: success()
    run: /easypanel-deploy
```

## Checklist Execução

- [ ] Verificar Dockerfile existe
- [ ] Lint Dockerfile (hadolint ou manual)
- [ ] Check .dockerignore
- [ ] Validar docker-compose.yml
- [ ] Verificar package.json (se Node.js)
- [ ] Check health endpoint
- [ ] Validar .gitignore
- [ ] Check .env.example
- [ ] Verificar CI/CD config
- [ ] Test local build (docker build)
- [ ] Calcular score
- [ ] Apply auto-fixes (se --fix)
- [ ] Gerar report

## Templates Disponíveis

Usar templates de:
`/media/ealmeida/Dados/Dev/Docs/EasyPanel-Deploy-Research/`

- TEMPLATE_Dockerfile_NodeJS_MultiStage
- TEMPLATE_docker-compose.yml
- TEMPLATE_gitea-workflow-deploy.yml
- TEMPLATE_health-endpoint.ts

---

**Versão:** 1.0.0 | **Autor:** Descomplicar® | **Data:** 2026-02-04

## Metadata (Desk CRM Task #65)

```
Tarefa: SKL: /easypanel-validate - Pre-deploy Validation
Milestone: 294 (Skills Claude Code)
Tags: skill(79), stackworkflow(75), claude-code(81), activo(116)
Responsáveis: Emanuel(1), AikTop(25)
Status: 4 (Em progresso) → 5 (Concluído)
```

---

**/** @author Descomplicar® | @link descomplicar.pt | @copyright 2026 **/

---

---

## Healing Log

Registo de erros conhecidos e como evitá-los. Lido automaticamente antes de executar.

```jsonl
{"date":"","issue":"","fix":"","source":"user|auto"}
```

*Adicionar nova linha após cada erro corrigido.*
