@saulwade/swl-ses 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Regla: Seguridad — Next.js
|
|
2
|
+
|
|
3
|
+
Next.js con App Router tiene características de seguridad integradas, pero
|
|
4
|
+
requiere configuración explícita para ser seguro en producción. Esta regla
|
|
5
|
+
cubre las decisiones que el desarrollador debe tomar conscientemente.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Validar variables de entorno al arrancar
|
|
10
|
+
|
|
11
|
+
Las variables de entorno no validadas causan errores crípticos en producción.
|
|
12
|
+
Validarlas al arrancar con un schema zod:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
// lib/env.ts
|
|
16
|
+
import { z } from 'zod'
|
|
17
|
+
|
|
18
|
+
const EnvSchema = z.object({
|
|
19
|
+
DATABASE_URL: z.string().url(),
|
|
20
|
+
NEXTAUTH_SECRET: z.string().min(32),
|
|
21
|
+
NEXTAUTH_URL: z.string().url(),
|
|
22
|
+
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
|
|
23
|
+
// Variables públicas (expuestas al cliente)
|
|
24
|
+
NEXT_PUBLIC_APP_URL: z.string().url(),
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const env = EnvSchema.parse(process.env)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- Este módulo se importa en `next.config.js` para que falle al buildear, no en runtime.
|
|
31
|
+
- Si la validación falla: el build se detiene con mensaje claro del campo faltante.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Server Actions: validar inputs server-side con zod
|
|
36
|
+
|
|
37
|
+
Las Server Actions son el nuevo endpoint de mutación. Reciben datos del cliente
|
|
38
|
+
y DEBEN validarlos como si fueran un endpoint de API público:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// app/facturas/actions.ts
|
|
42
|
+
'use server'
|
|
43
|
+
|
|
44
|
+
import { z } from 'zod'
|
|
45
|
+
import { auth } from '@/lib/auth'
|
|
46
|
+
|
|
47
|
+
const CrearFacturaSchema = z.object({
|
|
48
|
+
clienteId: z.coerce.number().int().positive(),
|
|
49
|
+
items: z.array(z.object({
|
|
50
|
+
sku: z.string().max(50),
|
|
51
|
+
qty: z.coerce.number().int().min(1).max(9999),
|
|
52
|
+
precio: z.coerce.number().positive(),
|
|
53
|
+
})).min(1),
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
export async function crearFactura(formData: FormData) {
|
|
57
|
+
// Verificar autenticación
|
|
58
|
+
const sesion = await auth()
|
|
59
|
+
if (!sesion?.user) throw new Error('No autorizado')
|
|
60
|
+
|
|
61
|
+
// Validar inputs
|
|
62
|
+
const validado = CrearFacturaSchema.safeParse(Object.fromEntries(formData))
|
|
63
|
+
if (!validado.success) {
|
|
64
|
+
return { errores: validado.error.flatten().fieldErrors }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Verificar que el cliente pertenece a la empresa del usuario (IDOR prevention)
|
|
68
|
+
const cliente = await obtenerClienteDeLaEmpresa(
|
|
69
|
+
validado.data.clienteId,
|
|
70
|
+
sesion.user.empresaId,
|
|
71
|
+
)
|
|
72
|
+
if (!cliente) return { errores: { clienteId: ['Cliente no encontrado'] } }
|
|
73
|
+
|
|
74
|
+
await facturaRepo.crear({ ...validado.data, empresaId: sesion.user.empresaId })
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## CSRF: protección nativa en Server Actions
|
|
81
|
+
|
|
82
|
+
- Las Server Actions incluyen protección CSRF automática de Next.js mediante
|
|
83
|
+
validación de origen. No requiere configuración adicional.
|
|
84
|
+
- Los Route Handlers (`route.ts`) NO tienen CSRF automático. Agregar verificación
|
|
85
|
+
de origen si reciben mutaciones desde formularios con cookies de sesión:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
// app/api/webhooks/stripe/route.ts
|
|
89
|
+
export async function POST(request: Request) {
|
|
90
|
+
// Webhooks externos usan firma, no CSRF
|
|
91
|
+
const firma = request.headers.get('stripe-signature')
|
|
92
|
+
await verificarFirmaStripe(firma, await request.text())
|
|
93
|
+
// ...
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Content Security Policy en next.config.js
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
// next.config.js
|
|
103
|
+
const securityHeaders = [
|
|
104
|
+
{ key: 'X-DNS-Prefetch-Control', value: 'on' },
|
|
105
|
+
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
|
|
106
|
+
{ key: 'X-Content-Type-Options', value: 'nosniff' },
|
|
107
|
+
{ key: 'Referrer-Policy', value: 'origin-when-cross-origin' },
|
|
108
|
+
{
|
|
109
|
+
key: 'Content-Security-Policy',
|
|
110
|
+
value: [
|
|
111
|
+
"default-src 'self'",
|
|
112
|
+
"script-src 'self' 'nonce-{NONCE}'",
|
|
113
|
+
"style-src 'self' 'unsafe-inline'",
|
|
114
|
+
"img-src 'self' data: https:",
|
|
115
|
+
"connect-src 'self' https://api.stripe.com",
|
|
116
|
+
].join('; '),
|
|
117
|
+
},
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
module.exports = {
|
|
121
|
+
async headers() {
|
|
122
|
+
return [{ source: '/(.*)', headers: securityHeaders }]
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## No exponer secretos al cliente
|
|
130
|
+
|
|
131
|
+
- Solo las variables con prefijo `NEXT_PUBLIC_` se exponen al bundle del cliente.
|
|
132
|
+
- NUNCA nombrar variables sensibles con `NEXT_PUBLIC_`:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# MAL — secreto expuesto al cliente
|
|
136
|
+
NEXT_PUBLIC_DATABASE_URL=postgresql://...
|
|
137
|
+
NEXT_PUBLIC_STRIPE_SECRET_KEY=sk_live_...
|
|
138
|
+
|
|
139
|
+
# BIEN — solo URLs públicas van con el prefijo
|
|
140
|
+
NEXT_PUBLIC_APP_URL=https://app.empresa.com
|
|
141
|
+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
|
|
142
|
+
|
|
143
|
+
# BIEN — secretos sin prefijo, solo disponibles en servidor
|
|
144
|
+
STRIPE_SECRET_KEY=sk_live_...
|
|
145
|
+
DATABASE_URL=postgresql://...
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Rate limiting en Route Handlers
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// lib/rate-limit.ts
|
|
154
|
+
import { LRUCache } from 'lru-cache'
|
|
155
|
+
|
|
156
|
+
const rateLimit = new LRUCache<string, number>({
|
|
157
|
+
max: 500,
|
|
158
|
+
ttl: 60 * 1000, // 1 minuto
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
export function checkRateLimit(ip: string, limit = 30): boolean {
|
|
162
|
+
const count = (rateLimit.get(ip) ?? 0) + 1
|
|
163
|
+
rateLimit.set(ip, count)
|
|
164
|
+
return count <= limit
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// app/api/contacto/route.ts
|
|
168
|
+
export async function POST(request: Request) {
|
|
169
|
+
const ip = request.headers.get('x-forwarded-for') ?? 'unknown'
|
|
170
|
+
if (!checkRateLimit(ip, 5)) {
|
|
171
|
+
return new Response('Too Many Requests', { status: 429 })
|
|
172
|
+
}
|
|
173
|
+
// ...
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Autenticación: NextAuth.js o Clerk
|
|
180
|
+
|
|
181
|
+
- NUNCA implementar autenticación custom con JWT manual y manejo de sesiones propio.
|
|
182
|
+
- **NextAuth.js (Auth.js v5)**: para proyectos con base de datos propia y necesidad
|
|
183
|
+
de control total.
|
|
184
|
+
- **Clerk**: para proyectos que priorizan velocidad de implementación y no tienen
|
|
185
|
+
requisitos de datos en territorio específico.
|
|
186
|
+
- Ambas opciones manejan correctamente: rotación de tokens, revocación de sesiones,
|
|
187
|
+
CSRF, cookies seguras y OAuth.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## dangerouslySetInnerHTML: sanitizar siempre
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
// MAL — XSS directo si contenido viene del usuario
|
|
195
|
+
<div dangerouslySetInnerHTML={{ __html: comentario.texto }} />
|
|
196
|
+
|
|
197
|
+
// BIEN — sanitizado antes de renderizar
|
|
198
|
+
import DOMPurify from 'isomorphic-dompurify'
|
|
199
|
+
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(comentario.texto) }} />
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
- Si `dangerouslySetInnerHTML` aparece en el codebase, es una señal de alerta
|
|
203
|
+
en code review que requiere verificación explícita de la fuente del contenido.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Checklist de seguridad antes de merge
|
|
208
|
+
|
|
209
|
+
- [ ] Variables de entorno validadas con zod en `lib/env.ts`
|
|
210
|
+
- [ ] Server Actions con validación zod y verificación de autenticación
|
|
211
|
+
- [ ] Server Actions con prevención de IDOR (datos filtrados por empresa/usuario)
|
|
212
|
+
- [ ] CSP configurada en `next.config.js`
|
|
213
|
+
- [ ] Sin variables sensibles con prefijo `NEXT_PUBLIC_`
|
|
214
|
+
- [ ] Rate limiting en Route Handlers públicos
|
|
215
|
+
- [ ] `dangerouslySetInnerHTML` con `DOMPurify.sanitize()` si existe
|
|
216
|
+
- [ ] `npm audit` sin vulnerabilidades HIGH o CRITICAL
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Regla: Testing — Next.js
|
|
2
|
+
|
|
3
|
+
Probar Next.js con App Router requiere estrategia porque existen tres tipos de
|
|
4
|
+
código distintos: Server Components (async, sin estado de React), Client Components
|
|
5
|
+
(con hooks y eventos) y Server Actions (funciones del servidor invocadas desde el cliente).
|
|
6
|
+
Esta regla define cómo cubrir cada uno.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Stack de testing
|
|
11
|
+
|
|
12
|
+
| Herramienta | Propósito |
|
|
13
|
+
|-------------|-----------|
|
|
14
|
+
| **Vitest** | Test runner para unit tests y componentes. Reemplaza Jest en proyectos nuevos. |
|
|
15
|
+
| **React Testing Library** | Renderizado y aserción de componentes. |
|
|
16
|
+
| **Playwright** | Tests end-to-end con browser real. |
|
|
17
|
+
| **MSW (Mock Service Worker)** | Mock de API en tests de integración. |
|
|
18
|
+
|
|
19
|
+
- Configuración de Vitest con soporte de React:
|
|
20
|
+
```ts
|
|
21
|
+
// vitest.config.ts
|
|
22
|
+
import { defineConfig } from 'vitest/config'
|
|
23
|
+
import react from '@vitejs/plugin-react'
|
|
24
|
+
|
|
25
|
+
export default defineConfig({
|
|
26
|
+
plugins: [react()],
|
|
27
|
+
test: {
|
|
28
|
+
environment: 'jsdom',
|
|
29
|
+
globals: true,
|
|
30
|
+
coverage: {
|
|
31
|
+
provider: 'v8',
|
|
32
|
+
thresholds: { lines: 80, functions: 80, branches: 80 },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Cobertura mínima: 80%
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
vitest run --coverage
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- CI falla si algún umbral (líneas, funciones, ramas) cae por debajo del 80%.
|
|
47
|
+
- La cobertura aplica sobre `components/`, `lib/`, `hooks/` y `actions/`.
|
|
48
|
+
No aplica sobre `app/**/page.tsx` ni `app/**/layout.tsx` (solo orquestan).
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Testing de Server Components
|
|
53
|
+
|
|
54
|
+
Los Server Components son funciones `async` que retornan JSX. Se testean
|
|
55
|
+
renderizando el resultado de la función directamente:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
// components/ResumenFactura.tsx
|
|
59
|
+
export async function ResumenFactura({ facturaId }: { facturaId: number }) {
|
|
60
|
+
const factura = await obtenerFactura(facturaId)
|
|
61
|
+
return (
|
|
62
|
+
<article>
|
|
63
|
+
<h2>{factura.folio}</h2>
|
|
64
|
+
<p>Total: ${factura.total}</p>
|
|
65
|
+
</article>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// components/ResumenFactura.test.tsx
|
|
70
|
+
import { render, screen } from '@testing-library/react'
|
|
71
|
+
import { ResumenFactura } from './ResumenFactura'
|
|
72
|
+
|
|
73
|
+
vi.mock('@/lib/facturas', () => ({
|
|
74
|
+
obtenerFactura: vi.fn().mockResolvedValue({
|
|
75
|
+
id: 1,
|
|
76
|
+
folio: 'FAC-00001',
|
|
77
|
+
total: 1160.0,
|
|
78
|
+
}),
|
|
79
|
+
}))
|
|
80
|
+
|
|
81
|
+
it('muestra el folio y total de la factura', async () => {
|
|
82
|
+
// Arrange + Act
|
|
83
|
+
const componente = await ResumenFactura({ facturaId: 1 })
|
|
84
|
+
render(componente)
|
|
85
|
+
|
|
86
|
+
// Assert
|
|
87
|
+
expect(screen.getByText('FAC-00001')).toBeInTheDocument()
|
|
88
|
+
expect(screen.getByText('Total: $1160')).toBeInTheDocument()
|
|
89
|
+
})
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Testing de Client Components con React Testing Library
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
// components/FormularioLogin.test.tsx
|
|
98
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
|
99
|
+
import userEvent from '@testing-library/user-event'
|
|
100
|
+
import { FormularioLogin } from './FormularioLogin'
|
|
101
|
+
|
|
102
|
+
describe('FormularioLogin', () => {
|
|
103
|
+
it('muestra error cuando el email tiene formato inválido', async () => {
|
|
104
|
+
// Arrange
|
|
105
|
+
const usuario = userEvent.setup()
|
|
106
|
+
render(<FormularioLogin />)
|
|
107
|
+
|
|
108
|
+
// Act
|
|
109
|
+
await usuario.type(screen.getByLabelText('Correo electrónico'), 'no-es-email')
|
|
110
|
+
await usuario.click(screen.getByRole('button', { name: /iniciar sesión/i }))
|
|
111
|
+
|
|
112
|
+
// Assert
|
|
113
|
+
await waitFor(() => {
|
|
114
|
+
expect(screen.getByRole('alert')).toHaveTextContent('Correo inválido')
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## MSW para mock de API en integración
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
// tests/mocks/handlers.ts
|
|
126
|
+
import { http, HttpResponse } from 'msw'
|
|
127
|
+
|
|
128
|
+
export const handlers = [
|
|
129
|
+
http.get('/api/facturas', () => {
|
|
130
|
+
return HttpResponse.json({
|
|
131
|
+
data: [{ id: 1, folio: 'FAC-001', total: 580.0 }],
|
|
132
|
+
meta: { total: 1, page: 1, per_page: 20 },
|
|
133
|
+
})
|
|
134
|
+
}),
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
// tests/setup.ts
|
|
138
|
+
import { setupServer } from 'msw/node'
|
|
139
|
+
import { handlers } from './mocks/handlers'
|
|
140
|
+
|
|
141
|
+
export const server = setupServer(...handlers)
|
|
142
|
+
beforeAll(() => server.listen())
|
|
143
|
+
afterEach(() => server.resetHandlers())
|
|
144
|
+
afterAll(() => server.close())
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Playwright para E2E
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
// e2e/facturas.spec.ts
|
|
153
|
+
import { test, expect } from '@playwright/test'
|
|
154
|
+
|
|
155
|
+
test('usuario puede emitir una factura', async ({ page }) => {
|
|
156
|
+
// Arrange — iniciar sesión
|
|
157
|
+
await page.goto('/login')
|
|
158
|
+
await page.fill('[name="email"]', 'admin@empresa.com')
|
|
159
|
+
await page.fill('[name="password"]', 'password-de-test')
|
|
160
|
+
await page.click('button[type="submit"]')
|
|
161
|
+
|
|
162
|
+
// Act
|
|
163
|
+
await page.goto('/facturas/nueva')
|
|
164
|
+
await page.selectOption('[name="clienteId"]', '1')
|
|
165
|
+
await page.click('button:has-text("Emitir factura")')
|
|
166
|
+
|
|
167
|
+
// Assert
|
|
168
|
+
await expect(page.locator('[data-testid="folio-factura"]')).toBeVisible()
|
|
169
|
+
await expect(page.locator('[data-testid="estatus-factura"]')).toHaveText('Emitida')
|
|
170
|
+
})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Snapshot testing: solo componentes estables
|
|
176
|
+
|
|
177
|
+
- Los snapshots de componentes se desactualizan con cada cambio de UI y generan
|
|
178
|
+
ruido en los diffs. Usar solo para componentes de diseño muy estables.
|
|
179
|
+
- Preferir aserciones explícitas con `getByRole`, `getByText`, `getByLabelText`.
|
|
180
|
+
- Si se usa snapshot: revisar el diff antes de hacer `--updateSnapshot`. No aceptar
|
|
181
|
+
ciegamente.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Checklist de testing antes de merge
|
|
186
|
+
|
|
187
|
+
- [ ] `vitest run --coverage` pasa con umbral 80%
|
|
188
|
+
- [ ] Server Components testeados con mock de sus dependencias de datos
|
|
189
|
+
- [ ] Client Components testeados con React Testing Library y `userEvent`
|
|
190
|
+
- [ ] MSW configurado para mocks de API en tests de integración
|
|
191
|
+
- [ ] Al menos 1 test E2E con Playwright por flujo crítico nuevo
|
|
192
|
+
- [ ] Sin `setTimeout` ni `sleep` en tests (usar `waitFor` de RTL)
|
|
193
|
+
- [ ] Snapshot tests solo en componentes explícitamente marcados como estables
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Regla: Estilo de Código — PHP
|
|
2
|
+
|
|
3
|
+
Aplica a todo código PHP del proyecto. PHP moderno (8.1+) es un lenguaje con
|
|
4
|
+
tipado estático opcional pero poderoso. Estas reglas maximizan la seguridad de
|
|
5
|
+
tipos, la legibilidad y la mantenibilidad en proyectos Laravel y PHP puro.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## PSR-12 como estándar de formato
|
|
10
|
+
|
|
11
|
+
- PSR-12 es el estándar de codificación obligatorio. Toda discrepancia de formato
|
|
12
|
+
se resuelve con el formateador automático, no con debate de equipo.
|
|
13
|
+
- Usar **Laravel Pint** en proyectos Laravel, o **PHP-CS-Fixer** en proyectos PHP puro.
|
|
14
|
+
- Ejecutar antes de cada commit:
|
|
15
|
+
```bash
|
|
16
|
+
./vendor/bin/pint --test # verifica sin modificar
|
|
17
|
+
./vendor/bin/pint # aplica correcciones
|
|
18
|
+
```
|
|
19
|
+
- CI debe fallar si `pint --test` produce diferencias.
|
|
20
|
+
- El archivo `pint.json` (o `.php-cs-fixer.php`) se versiona en el repositorio.
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## strict_types en todos los archivos
|
|
25
|
+
|
|
26
|
+
- Todo archivo PHP DEBE comenzar con la declaración de tipos estrictos:
|
|
27
|
+
```php
|
|
28
|
+
<?php
|
|
29
|
+
|
|
30
|
+
declare(strict_types=1);
|
|
31
|
+
```
|
|
32
|
+
- Sin `declare(strict_types=1)`: PHP convierte tipos silenciosamente y produce bugs difíciles de rastrear.
|
|
33
|
+
- No hay excepciones. Ni en scripts de migración, ni en helpers, ni en tests.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Type hints obligatorios
|
|
38
|
+
|
|
39
|
+
- Todo parámetro, retorno y propiedad de clase lleva tipo declarado.
|
|
40
|
+
|
|
41
|
+
**MAL — sin tipos:**
|
|
42
|
+
```php
|
|
43
|
+
function calcularTotal($items, $descuento) {
|
|
44
|
+
return array_sum(array_column($items, 'precio')) * (1 - $descuento);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**BIEN — con tipos:**
|
|
49
|
+
```php
|
|
50
|
+
function calcularTotal(array $items, float $descuento): float
|
|
51
|
+
{
|
|
52
|
+
return array_sum(array_column($items, 'precio')) * (1 - $descuento);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- Tipos de retorno `void` cuando la función no retorna valor.
|
|
57
|
+
- `never` cuando la función siempre lanza excepción o termina el proceso.
|
|
58
|
+
- `mixed` solo cuando es genuinamente imposible determinar el tipo.
|
|
59
|
+
Si aparece `mixed`: señal de deuda técnica, documentar con `// TODO:`.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Readonly properties (PHP 8.2+)
|
|
64
|
+
|
|
65
|
+
- Propiedades que no cambian después de la construcción se declaran `readonly`:
|
|
66
|
+
|
|
67
|
+
```php
|
|
68
|
+
// MAL — propiedad mutable que nunca debería mutar
|
|
69
|
+
class Factura
|
|
70
|
+
{
|
|
71
|
+
public string $folio;
|
|
72
|
+
|
|
73
|
+
public function __construct(string $folio)
|
|
74
|
+
{
|
|
75
|
+
$this->folio = $folio;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// BIEN — inmutabilidad declarada explícitamente
|
|
80
|
+
class Factura
|
|
81
|
+
{
|
|
82
|
+
public function __construct(
|
|
83
|
+
public readonly string $folio,
|
|
84
|
+
public readonly \DateTimeImmutable $fechaEmision,
|
|
85
|
+
) {}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Enums nativos (PHP 8.1+)
|
|
92
|
+
|
|
93
|
+
- Reemplazar constantes de clase y strings mágicos con enums nativos:
|
|
94
|
+
|
|
95
|
+
```php
|
|
96
|
+
// MAL — constantes como pseudo-enum
|
|
97
|
+
class EstatusFactura
|
|
98
|
+
{
|
|
99
|
+
const BORRADOR = 'borrador';
|
|
100
|
+
const EMITIDA = 'emitida';
|
|
101
|
+
const CANCELADA = 'cancelada';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// BIEN — enum nativo con métodos
|
|
105
|
+
enum EstatusFactura: string
|
|
106
|
+
{
|
|
107
|
+
case Borrador = 'borrador';
|
|
108
|
+
case Emitida = 'emitida';
|
|
109
|
+
case Cancelada = 'cancelada';
|
|
110
|
+
|
|
111
|
+
public function esTerminal(): bool
|
|
112
|
+
{
|
|
113
|
+
return $this === self::Cancelada;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Named arguments para funciones con muchos parámetros
|
|
121
|
+
|
|
122
|
+
```php
|
|
123
|
+
// MAL — posicional, ilegible
|
|
124
|
+
$reporte = generarReporte(true, false, null, 'pdf', 100, 1);
|
|
125
|
+
|
|
126
|
+
// BIEN — named arguments, autodocumentado
|
|
127
|
+
$reporte = generarReporte(
|
|
128
|
+
incluirImpuestos: true,
|
|
129
|
+
incluirDescuentos: false,
|
|
130
|
+
filtroEmpresa: null,
|
|
131
|
+
formato: 'pdf',
|
|
132
|
+
limitePaginas: 100,
|
|
133
|
+
pagina: 1,
|
|
134
|
+
);
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Match expression sobre switch
|
|
140
|
+
|
|
141
|
+
```php
|
|
142
|
+
// MAL — switch verboso
|
|
143
|
+
switch ($estatus) {
|
|
144
|
+
case 'activo':
|
|
145
|
+
$etiqueta = 'Activo';
|
|
146
|
+
break;
|
|
147
|
+
case 'inactivo':
|
|
148
|
+
$etiqueta = 'Inactivo';
|
|
149
|
+
break;
|
|
150
|
+
default:
|
|
151
|
+
throw new \InvalidArgumentException("Estatus desconocido: $estatus");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// BIEN — match con exhaustividad
|
|
155
|
+
$etiqueta = match ($estatus) {
|
|
156
|
+
'activo' => 'Activo',
|
|
157
|
+
'inactivo' => 'Inactivo',
|
|
158
|
+
default => throw new \InvalidArgumentException("Estatus desconocido: $estatus"),
|
|
159
|
+
};
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Null safe operator en cadenas
|
|
165
|
+
|
|
166
|
+
```php
|
|
167
|
+
// MAL — verificaciones manuales de null en cadena
|
|
168
|
+
$ciudad = null;
|
|
169
|
+
if ($factura !== null && $factura->cliente !== null && $factura->cliente->direccion !== null) {
|
|
170
|
+
$ciudad = $factura->cliente->direccion->ciudad;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// BIEN — null safe operator
|
|
174
|
+
$ciudad = $factura?->cliente?->direccion?->ciudad;
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Arrow functions para closures simples
|
|
180
|
+
|
|
181
|
+
```php
|
|
182
|
+
// MAL — closure verboso para transformación simple
|
|
183
|
+
$totales = array_map(function ($factura) {
|
|
184
|
+
return $factura->total;
|
|
185
|
+
}, $facturas);
|
|
186
|
+
|
|
187
|
+
// BIEN — arrow function concisa
|
|
188
|
+
$totales = array_map(fn($factura) => $factura->total, $facturas);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Convenciones de nombres
|
|
194
|
+
|
|
195
|
+
| Elemento | Convención | Ejemplo |
|
|
196
|
+
|----------|-----------|---------|
|
|
197
|
+
| Clases, interfaces, traits, enums | PascalCase | `FacturaService`, `Pagable` |
|
|
198
|
+
| Métodos y funciones | camelCase | `calcularTotal()`, `obtenerCliente()` |
|
|
199
|
+
| Variables y parámetros | camelCase | `$totalFactura`, `$clienteActivo` |
|
|
200
|
+
| Constantes de clase | SCREAMING_SNAKE_CASE | `MAX_INTENTOS`, `TASA_IVA` |
|
|
201
|
+
| Propiedades de modelo | camelCase en PHP, snake_case en BD | `$fechaEmision` ↔ `fecha_emision` |
|
|
202
|
+
|
|
203
|
+
- Booleanos: prefijo `es`, `tiene`, `puede`, `esta`:
|
|
204
|
+
`$esActivo`, `$tieneSaldo`, `$puedeEditar`.
|
|
205
|
+
- Colecciones: plural del elemento: `$facturas`, `$usuariosActivos`.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Longitud máxima de método: 40 líneas
|
|
210
|
+
|
|
211
|
+
- Un método que supera 40 líneas hace más de una cosa. Extraer métodos privados
|
|
212
|
+
con nombres descriptivos.
|
|
213
|
+
- Complejidad ciclomática máxima: 5. Más de 5 ramas: refactorizar.
|
|
214
|
+
- Parámetros de método: máximo 4. Si se necesitan más, usar un DTO o array tipado.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Checklist de estilo antes de hacer commit
|
|
219
|
+
|
|
220
|
+
- [ ] `declare(strict_types=1)` en todos los archivos PHP nuevos
|
|
221
|
+
- [ ] `./vendor/bin/pint --test` pasa sin diferencias
|
|
222
|
+
- [ ] Todo parámetro, retorno y propiedad tiene tipo declarado
|
|
223
|
+
- [ ] Sin `mixed` sin comentario justificativo
|
|
224
|
+
- [ ] Enums nativos en lugar de constantes de clase para dominios cerrados
|
|
225
|
+
- [ ] `match` en lugar de `switch` donde aplica
|
|
226
|
+
- [ ] Sin `null` checks manuales en cadena cuando `?->` funciona
|
|
227
|
+
- [ ] Métodos <= 40 líneas
|
|
228
|
+
- [ ] Sin abreviaciones en nombres de variables ni métodos
|