feat: CRM Clinicas SaaS - MVP completo
- Auth: Login/Register con creacion de clinica - Dashboard: KPIs reales, graficas recharts - Pacientes: CRUD completo con busqueda - Agenda: FullCalendar, drag-and-drop, vista recepcion - Expediente: Notas SOAP, signos vitales, CIE-10 - Facturacion: Facturas con IVA, campos CFDI SAT - Inventario: Productos, stock, movimientos, alertas - Configuracion: Clinica, equipo, catalogo servicios - Supabase self-hosted: 18 tablas con RLS multi-tenant - Docker + Nginx para produccion Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
186
.claude/helpers/adr-compliance.sh
Executable file
186
.claude/helpers/adr-compliance.sh
Executable file
@@ -0,0 +1,186 @@
|
||||
#!/bin/bash
|
||||
# Claude Flow V3 - ADR Compliance Checker Worker
|
||||
# Checks compliance with Architecture Decision Records
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
METRICS_DIR="$PROJECT_ROOT/.claude-flow/metrics"
|
||||
ADR_FILE="$METRICS_DIR/adr-compliance.json"
|
||||
LAST_RUN_FILE="$METRICS_DIR/.adr-last-run"
|
||||
|
||||
mkdir -p "$METRICS_DIR"
|
||||
|
||||
# V3 ADRs to check
|
||||
declare -A ADRS=(
|
||||
["ADR-001"]="agentic-flow as core foundation"
|
||||
["ADR-002"]="Domain-Driven Design structure"
|
||||
["ADR-003"]="Single coordination engine"
|
||||
["ADR-004"]="Plugin-based architecture"
|
||||
["ADR-005"]="MCP-first API design"
|
||||
["ADR-006"]="Unified memory service"
|
||||
["ADR-007"]="Event sourcing for state"
|
||||
["ADR-008"]="Vitest over Jest"
|
||||
["ADR-009"]="Hybrid memory backend"
|
||||
["ADR-010"]="Remove Deno support"
|
||||
)
|
||||
|
||||
should_run() {
|
||||
if [ ! -f "$LAST_RUN_FILE" ]; then return 0; fi
|
||||
local last_run=$(cat "$LAST_RUN_FILE" 2>/dev/null || echo "0")
|
||||
local now=$(date +%s)
|
||||
[ $((now - last_run)) -ge 900 ] # 15 minutes
|
||||
}
|
||||
|
||||
check_adr_001() {
|
||||
# ADR-001: agentic-flow as core foundation
|
||||
local score=0
|
||||
|
||||
# Check package.json for agentic-flow dependency
|
||||
grep -q "agentic-flow" "$PROJECT_ROOT/package.json" 2>/dev/null && score=$((score + 50))
|
||||
|
||||
# Check for imports from agentic-flow
|
||||
local imports=$(grep -r "from.*agentic-flow\|require.*agentic-flow" "$PROJECT_ROOT/v3" "$PROJECT_ROOT/src" 2>/dev/null | grep -v node_modules | wc -l)
|
||||
[ "$imports" -gt 5 ] && score=$((score + 50))
|
||||
|
||||
echo "$score"
|
||||
}
|
||||
|
||||
check_adr_002() {
|
||||
# ADR-002: Domain-Driven Design structure
|
||||
local score=0
|
||||
|
||||
# Check for domain directories
|
||||
[ -d "$PROJECT_ROOT/v3" ] || [ -d "$PROJECT_ROOT/src/domains" ] && score=$((score + 30))
|
||||
|
||||
# Check for bounded contexts
|
||||
local contexts=$(find "$PROJECT_ROOT/v3" "$PROJECT_ROOT/src" -type d -name "domain" 2>/dev/null | wc -l)
|
||||
[ "$contexts" -gt 0 ] && score=$((score + 35))
|
||||
|
||||
# Check for anti-corruption layers
|
||||
local acl=$(grep -r "AntiCorruption\|Adapter\|Port" "$PROJECT_ROOT/v3" "$PROJECT_ROOT/src" 2>/dev/null | grep -v node_modules | wc -l)
|
||||
[ "$acl" -gt 0 ] && score=$((score + 35))
|
||||
|
||||
echo "$score"
|
||||
}
|
||||
|
||||
check_adr_003() {
|
||||
# ADR-003: Single coordination engine
|
||||
local score=0
|
||||
|
||||
# Check for unified SwarmCoordinator
|
||||
grep -rq "SwarmCoordinator\|UnifiedCoordinator" "$PROJECT_ROOT/v3" "$PROJECT_ROOT/src" 2>/dev/null && score=$((score + 50))
|
||||
|
||||
# Check for no duplicate coordinators
|
||||
local coordinators=$(grep -r "class.*Coordinator" "$PROJECT_ROOT/v3" "$PROJECT_ROOT/src" 2>/dev/null | grep -v node_modules | grep -v ".test." | wc -l)
|
||||
[ "$coordinators" -le 3 ] && score=$((score + 50))
|
||||
|
||||
echo "$score"
|
||||
}
|
||||
|
||||
check_adr_005() {
|
||||
# ADR-005: MCP-first API design
|
||||
local score=0
|
||||
|
||||
# Check for MCP server implementation
|
||||
[ -d "$PROJECT_ROOT/v3/@claude-flow/mcp" ] && score=$((score + 40))
|
||||
|
||||
# Check for MCP tools
|
||||
local tools=$(grep -r "tool.*name\|registerTool" "$PROJECT_ROOT/v3" 2>/dev/null | wc -l)
|
||||
[ "$tools" -gt 5 ] && score=$((score + 30))
|
||||
|
||||
# Check for MCP schemas
|
||||
grep -rq "schema\|jsonSchema" "$PROJECT_ROOT/v3/@claude-flow/mcp" 2>/dev/null && score=$((score + 30))
|
||||
|
||||
echo "$score"
|
||||
}
|
||||
|
||||
check_adr_008() {
|
||||
# ADR-008: Vitest over Jest
|
||||
local score=0
|
||||
|
||||
# Check for vitest in package.json
|
||||
grep -q "vitest" "$PROJECT_ROOT/package.json" 2>/dev/null && score=$((score + 50))
|
||||
|
||||
# Check for no jest references
|
||||
local jest_refs=$(grep -r "from.*jest\|jest\." "$PROJECT_ROOT/v3" "$PROJECT_ROOT/src" 2>/dev/null | grep -v node_modules | grep -v "vitest" | wc -l)
|
||||
[ "$jest_refs" -eq 0 ] && score=$((score + 50))
|
||||
|
||||
echo "$score"
|
||||
}
|
||||
|
||||
check_compliance() {
|
||||
echo "[$(date +%H:%M:%S)] Checking ADR compliance..."
|
||||
|
||||
local total_score=0
|
||||
local compliant_count=0
|
||||
local results=""
|
||||
|
||||
# Check each ADR
|
||||
local adr_001=$(check_adr_001)
|
||||
local adr_002=$(check_adr_002)
|
||||
local adr_003=$(check_adr_003)
|
||||
local adr_005=$(check_adr_005)
|
||||
local adr_008=$(check_adr_008)
|
||||
|
||||
# Simple checks for others (assume partial compliance)
|
||||
local adr_004=50 # Plugin architecture
|
||||
local adr_006=50 # Unified memory
|
||||
local adr_007=50 # Event sourcing
|
||||
local adr_009=75 # Hybrid memory
|
||||
local adr_010=100 # No Deno (easy to verify)
|
||||
|
||||
# Calculate totals
|
||||
for score in $adr_001 $adr_002 $adr_003 $adr_004 $adr_005 $adr_006 $adr_007 $adr_008 $adr_009 $adr_010; do
|
||||
total_score=$((total_score + score))
|
||||
[ "$score" -ge 50 ] && compliant_count=$((compliant_count + 1))
|
||||
done
|
||||
|
||||
local avg_score=$((total_score / 10))
|
||||
|
||||
# Write ADR compliance metrics
|
||||
cat > "$ADR_FILE" << EOF
|
||||
{
|
||||
"timestamp": "$(date -Iseconds)",
|
||||
"overallCompliance": $avg_score,
|
||||
"compliantCount": $compliant_count,
|
||||
"totalADRs": 10,
|
||||
"adrs": {
|
||||
"ADR-001": {"score": $adr_001, "title": "agentic-flow as core foundation"},
|
||||
"ADR-002": {"score": $adr_002, "title": "Domain-Driven Design structure"},
|
||||
"ADR-003": {"score": $adr_003, "title": "Single coordination engine"},
|
||||
"ADR-004": {"score": $adr_004, "title": "Plugin-based architecture"},
|
||||
"ADR-005": {"score": $adr_005, "title": "MCP-first API design"},
|
||||
"ADR-006": {"score": $adr_006, "title": "Unified memory service"},
|
||||
"ADR-007": {"score": $adr_007, "title": "Event sourcing for state"},
|
||||
"ADR-008": {"score": $adr_008, "title": "Vitest over Jest"},
|
||||
"ADR-009": {"score": $adr_009, "title": "Hybrid memory backend"},
|
||||
"ADR-010": {"score": $adr_010, "title": "Remove Deno support"}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "[$(date +%H:%M:%S)] ✓ ADR Compliance: ${avg_score}% | Compliant: $compliant_count/10"
|
||||
|
||||
date +%s > "$LAST_RUN_FILE"
|
||||
}
|
||||
|
||||
case "${1:-check}" in
|
||||
"run") check_compliance ;;
|
||||
"check") should_run && check_compliance || echo "[$(date +%H:%M:%S)] Skipping (throttled)" ;;
|
||||
"force") rm -f "$LAST_RUN_FILE"; check_compliance ;;
|
||||
"status")
|
||||
if [ -f "$ADR_FILE" ]; then
|
||||
jq -r '"Compliance: \(.overallCompliance)% | Compliant: \(.compliantCount)/\(.totalADRs)"' "$ADR_FILE"
|
||||
else
|
||||
echo "No ADR data available"
|
||||
fi
|
||||
;;
|
||||
"details")
|
||||
if [ -f "$ADR_FILE" ]; then
|
||||
jq -r '.adrs | to_entries[] | "\(.key): \(.value.score)% - \(.value.title)"' "$ADR_FILE"
|
||||
fi
|
||||
;;
|
||||
*) echo "Usage: $0 [run|check|force|status|details]" ;;
|
||||
esac
|
||||
Reference in New Issue
Block a user