APS-Framework/aps-template

Plantilla de proyecto APS Framework: agentes, skills, comandos y scripts para crear aplicaciones web .NET Azure Functions y ASP.NET Core con paquetes APS.

¿Qué es aps-template?

Este skill guía al orquestador de IA en la creación de nuevas funcionalidades (no modificaciones) dentro de proyectos .NET que usan el framework APS. Su objetivo principal es asegurar que, antes de escribir cualquier código, se realice un análisis exhaustivo de reutilización, configuración e impacto, evitando duplicidad y garantizando la coherencia con la arquitectura existente. El skill soporta hosts como Azure Functions (modo aislado), ASP.NET Core Web Apps y librerías NuGet, y define un proceso estructurado en fases que va desde la validación inicial de la estructura del proyecto hasta la verificación final con pruebas unitarias y de regresión. Es útil para desarrolladores que trabajan con el ecosistema APS, ya que automatiza decisiones de diseño como la creación de endpoints, servicios, handlers de eventos y opciones de configuración, integrando workers especializados como `@refactor-worker-contracts` y `@refactor-verifier` para mantener la calidad y evitar breaking changes.

Compatible con~Claude Code~Codex CLI~Cursor✓OpenCode
npx skills add APS-Framework/aps-template

Installed? Explore more Investigación y análisis de datos skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Qué hago

Guío al orquestador para crear funcionalidades nuevas (no modificar existentes) con análisis previo de reutilización, configuración y compatibilidad. A diferencia de los refactors, aquí no hay código previo que preservar: el diseño empieza desde los requisitos del usuario.

Cuándo usar este skill (en lugar de refactor-protocol):

  • Usuario pide un endpoint, servicio, job, handler, evento o configuración que NO existe
  • La tarea es creación pura, no modificación de comportamiento existente
  • El resultado añade archivos al repositorio, no cambia la signatura de los existentes

Cuándo NO usar este skill (usar refactor-protocol en su lugar):

  • Modificar signatura de un servicio existente
  • Cambiar comportamiento de un endpoint que ya existe
  • Renombrar, extraer o mover código

FASE 0 — Validación de estructura (siempre primera)

  1. Cargar el skill project-structure y ejecutar la validación completa
  2. Detectar el tipo de host: FUNCTIONS | WEBAPP | NUGET_LIBRARY
  3. Actuar según el resultado:
EstadoAcción
HARD_BLOCKDetener. Informar al usuario.
NUGET_LIBRARYCrear un endpoint HTTP es inesperado. Preguntar: "¿Quieres añadir una operación pública a la librería o realmente hay un host que no he detectado?"
PREGUNTAResolver las preguntas antes de continuar
OK / WARNINGContinuar a FASE 1

FASE 1 — Recopilación de requisitos

El orquestador infiere lo que pueda de la descripción del usuario ($ARGUMENTS) y solo pregunta lo que no esté claro. No hacer preguntas cuya respuesta ya esté en la descripción.

1.1 Nombre, propósito y tipo de feature

  • Endpoint HTTP (Function/Controller): [VERBO] /ruta — descripción
  • Servicio de dominio: nombre del servicio y responsabilidad
  • Job/Event handler: trigger + acción
  • Opción de configuración: nombre de la opción y su propósito

1.2 Clasificación READ vs MUTATION

Determinar si la feature muta estado o es solo lectura. Esto afecta a:

  • Dónde van los DTOs de response
  • Si se requiere transacción / idempotencia
  • Qué tests se necesitan
TipoCaracterísticasImplicación
READ-ONLYGET, devuelve datos existentes, no escribeDTOs efímeros, tests mínimos
MUTATIONPOST/PUT/DELETE, escribe o cambia estadoRequiere tests de éxito + error

1.3 Recopilación de input/output esperado

  • Request: estructura del body o query params
  • Response: estructura del body de respuesta, status codes
  • Errores: qué errores se deben mapear a qué status codes

FASE 1.5 — Análisis de reutilización (CRÍTICA, no saltarse)

Objetivo: detectar si la feature ya existe parcial o totalmente antes de crear nada.

Pasos

  1. Buscar servicios existentes en *.Impl/ con @explore usando el dominio de la feature
  2. Buscar métodos candidatos que cubran el 80%+ del comportamiento requerido:
    • ¿Hay un método que ya devuelve el dato necesario con un filtro trivial?
    • ¿Hay un método que se podría sobrecargar para añadir el caso?
  3. Buscar endpoints similares en *.API/ con la misma forma de request/response

Árbol de decisión

¿Existe método que cubre 100% del caso?
└── SÍ → NO crear método nuevo. Crear solo:
        · Endpoint (Function/Controller) en *.API/
        · DTO Request/Response exclusivo en *.API/
        · Test del shape del response

¿Existe método casi-idóneo (filtro, paginación, orden)?
├── SÍ → considerar:
│   ├── Añadir parámetro opcional al método existente (con valor por defecto)
│   ├── Crear overload con signatura más específica
│   └── Crear método de extensión que envuelva al existente
└── NO → continuar con creación de método nuevo

¿Existe servicio relacionado pero diferente (e.g., similar responsabilidad)?
├── SÍ → preguntar al usuario: "¿Extiendo [CSXxxService] o creo uno nuevo [CSYyyService]?"
└── NO → crear servicio nuevo

Salida esperada de esta fase

Una de estas tres decisiones, presentada al usuario antes de continuar:

  1. Reutilización pura: la feature se implementa como wrapper de un método existente
  2. Extensión: añadir overload/método a un servicio existente
  3. Creación nueva: servicio y métodos nuevos (justificar por qué no se puede reutilizar)

FASE 1.6 — Análisis de configuración (NUEVA)

Objetivo: detectar si la feature requiere parámetros configurables y, si sí, dónde definirlos.

Preguntas clave

  1. ¿La feature tiene valores por defecto razonables sin configuración externa?
  2. ¿Hay umbrales, paginación, timeouts, o flags que deberían ser configurables por entorno?
  3. ¿Se conecta a un sistema externo con URL/clave/secret?
  4. ¿Necesita feature flags para rollout gradual?

Árbol de decisión

¿La feature requiere configuración?
├── NO → no crear IXxxOptions, no tocar AddCustomConfiguration
└── SÍ → continuar

¿Qué tipo de configuración?
├── Connection string o secreto
│   └── Usar IConfiguration con nombre en appsettings.json (gestionado por AddCustomConfiguration)
├── Valor simple (umbral, timeout, flag)
│   └── Crear IXxxOptions en *.Impl/ (interface) + añadir a AddCustomConfiguration<T>("key")
└── Lista de valores (allowed origins, mappings)
    └── Crear IXxxOptions con propiedad de tipo IEnumerable<T>

Convención del proyecto

El proyecto usa AddCustomConfiguration<IXxxOptions>("config-section") en IoCExtensions.cs (líneas 43-45 del proyecto actual). Las interfaces viven en *.Impl/ y se referencian desde *.Impl/Services/.

Salida esperada

Si la feature requiere configuración, presentar al usuario:

  • Nombre de la interface (e.g., IPendingPaymentOptions)
  • Propiedades con sus tipos y valores por defecto
  • Sección en appsettings.json (e.g., "RAMBLA.PendingPayment")
  • Modificación de IoCExtensions.AddCSLevelBooking()

Si NO requiere, indicarlo explícitamente en el plan.


FASE 1.7 — Análisis de impacto en API pública

Objetivo: evitar romper consumers existentes.

Si la feature reutiliza un método existente

  • ¿El método se mantiene con la misma signatura? → sin impacto
  • ¿Se añade un parámetro opcional? → verificar que ningún call site se rompa
  • ¿Se añade un overload? → verificar que el compilador resuelva sin ambigüedad
  • ¿Se renombra? → buscar todos los call sites con grep y migrar

Si la feature añade un servicio nuevo

  • ¿El servicio se registra en DI? → asegurar registro en IoCExtensions
  • ¿Algún servicio existente tiene dependencia circular potencial? → verificar

Si la feature añade un endpoint nuevo

  • ¿La ruta colisiona con otra ruta existente? → verificar
  • ¿El método HTTP es coherente con REST? (GET para lectura, POST para mutación)

FASE 1.8 — PREFLIGHT de tests de regresión (obligatorio)

Objetivo: antes de generar código nuevo o modificar existente, verificar que los componentes que se van a tocar (aunque sea tangencialmente) tienen cobertura de tests. Si no la tienen, crearla y ejecutarla antes de iniciar la implementación.

Pasos

  1. Identificar superficie tangencial: a partir de FASE 1.5 (reutilización vs extensión vs nuevo), listar:

    • Servicios existentes cuyos métodos se van a extender o sobrecargar
    • Interfaces existentes que se van a modificar
    • Endpoints existentes que pueden verse afectados por routing/DI
    • Cualquier archivo existente que se va a editar (no crear)
  2. Para cada componente existente que se va a tocar:

    • Buscar tests en src/*.Test*/** que lo ejerciten
    • Si tiene cobertura → OK, continuar
    • Si no tiene cobertura → HARD BLOCK:
      • Invocar @refactor-worker-tests para crear tests de caracterización del comportamiento actual
      • Invocar @refactor-verifier para confirmar que pasan en verde
      • Commit separado:
        test(characterization): add characterization tests for <clases>
        
  3. Si la feature es 100% creación nueva (no toca archivos existentes):

    • No hay superficie de regresión → omitir PREFLIGHT
    • Pero los tests de la feature nueva se crean en FASE 4 y deben pasar en FASE 5

Criterio de cierre (FASE 5)

Para dar por correcta la feature, @refactor-verifier debe confirmar que pasan:

  1. Tests nuevos de la feature (servicio + endpoint)
  2. Tests existentes de los componentes tangenciales (regresión)

Si cualquiera falla, la feature no puede cerrarse.


FASE 2 — Árbol de decisión: qué crear y dónde

Aplicar la decisión de la FASE 1.5 (reutilización / extensión / nuevo) más la FASE 1.6 (config).

Para endpoint READ-ONLY con reutilización

*.API/
  + {Nombre}Function.cs       — Function/Controller nuevo
  + {Nombre}Request.cs        — exclusivo de presentación
  + {Nombre}Response.cs       — exclusivo de presentación
*.Test*/
  + {Nombre}FunctionTests.cs  — test de shape del response (NO lógica)

Para endpoint MUTATION con servicio nuevo

*.Contracts/
  + ICS{Nombre}Service.cs     — interfaz del servicio
  + {Nombre}Request.cs        — si Request compartido
  + {Nombre}Response.cs       — si Response compartido
*.Impl/
  + CS{Nombre}Service.cs      — implementación
  + I{Nombre}Options.cs       — SOLO si FASE 1.6 detectó config
*.API/
  + {Nombre}Function.cs       — Function/Controller
  + {Nombre}Request.cs        — exclusivo (si no se puso en Contracts)
  + {Nombre}Response.cs       — exclusivo (si no se puso en Contracts)
*.Test*/
  + CS{Nombre}ServiceTests.cs — happy path + al menos un error

Para extensión de servicio existente

*.Contracts/
  ~ ICS{Nombre}Service.cs     — añadir firma del método (o crear overload)
*.Impl/
  ~ CS{Nombre}Service.cs      — implementar el nuevo método/overload
*.API/
  + {Nombre}Function.cs       — Function/Controller nuevo
  + {Nombre}Request.cs        — si exclusivo
  + {Nombre}Response.cs       — si exclusivo
*.Test*/
  + (o ~) tests del servicio — añadir caso para el nuevo método

FASE 3 — Plan de creación

Antes de invocar workers, el orquestador presenta este plan al usuario y espera confirmación explícita:

[PLAN DE CREACIÓN] Feature: <nombre> — <descripción breve>
Host: <FUNCTIONS | WEBAPP>
Clasificación: <READ-ONLY | MUTATION>
Estrategia: <REUTILIZACIÓN | EXTENSIÓN | NUEVO>

Análisis de reutilización (FASE 1.5):
  · Servicio candidato: <ICSXxxService> o "ninguno"
  · Método candidato: <XxxService.YyyMethod> o "ninguno"
  · Decisión: <REUTILIZACIÓN | EXTENSIÓN | NUEVO>

Análisis de configuración (FASE 1.6):
  · Requiere config: <SÍ | NO>
  · Si sí: <IXxxOptions + sección appsettings>

Impacto en API pública (FASE 1.7):
  · Call sites afectados: <lista> o "ninguno"
  · Breaking change: <SÍ | NO>

Artefactos a crear:

  *.Contracts/ ([N] archivos):
    + ICS{Nombre}Service.cs    — nueva interfaz (o: añadir método a IXxx)
    + {Nombre}Request.cs       — si tipo compartido
    + {Nombre}Response.cs      — si tipo compartido

  *.Impl/ ([N] archivos):
    + CS{Nombre}Service.cs     — implementación del servicio
    + I{Nombre}Options.cs      — SOLO si requiere config (FASE 1.6)

  *.API/ ([N] archivos):
    + {Nombre}Function.cs      — Azure Function (o: {Nombre}Controller.cs)
    + {Nombre}Request.cs       — si tipo exclusivo
    + {Nombre}Response.cs      — si tipo exclusivo

  *.Test*/ ([N] archivos):
    + CS{Nombre}ServiceTests.cs — tests del servicio (happy path + error)
    + {Nombre}FunctionTests.cs  — tests del endpoint (si aplica)

Modificaciones a archivos existentes:
  ~ src/.../IoCExtensions.cs   — registrar servicio y opciones (si aplica)

Orden de ejecución: Contracts → Impl → Presentation → Tests

¿Proceder?

Sin aprobación explícita del usuario, no invocar workers.


FASE 4 — Ejecución

Orden de workers

  1. @refactor-worker-contracts — solo si hay nuevos tipos o signaturas en *.Contracts/
  2. @refactor-worker-impl — siempre que haya código en *.Impl/
  3. @refactor-worker-presentation — siempre que haya un endpoint
  4. @refactor-worker-tests — siempre al final

Nota: NO se invoca @refactor-worker-crosscutting salvo que la feature exponga un nuevo Service Gateway. Esto es un caso raro en creación; suele ser en refactors.

Instrucciones a cada worker

Incluir en el prompt:

  • El plan completo (FASE 3)
  • Los patrones del proyecto: leer un archivo similar antes de crear
  • La lista exacta de archivos con su contenido esperado
  • Si FASE 1.6 detectó config: el path de IXxxOptions y la sección de configuración

FASE 5 — Verificación y commit

  1. Invocar @refactor-verifier
  2. Si PASS → proponer commit con formato:
    feat(<scope>): add <nombre-corto> feature
    
    - Added ICS{Nombre}Service interface and CS{Nombre}Service implementation
    - Added {VERB} /{ruta} Function/Controller
    - Added {Nombre}Request/{Nombre}Response contracts
    - Added I{Nombre}Options for new configuration (si aplica)
    - Added unit tests for CS{Nombre}Service
    
  3. Si FAIL → identificar capa fallida, re-invocar worker, re-verificar

Patrones por host

FUNCTIONS — Azure Functions Isolated Worker

Antes de crear la Function, leer una Function HTTP existente y copiar su estilo. Ejemplo típico:

public class {Nombre}Function
{
    private readonly I{Nombre}Service _{campo};

    public {Nombre}Function(I{Nombre}Service {campo}) => _{campo} = {campo};

    [Function("{Nombre}Function")]
    public async Task<HttpResponseData> RunAsync(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = "{ruta}")] HttpRequestData req)
    {
        var request = await req.ReadFromJsonAsync<{Nombre}Request>();
        var result = await _{campo}.ExecuteAsync(request);
        var response = req.CreateResponse(HttpStatusCode.OK);
        await response.WriteAsJsonAsync(result);
        return response;
    }
}

Verificar antes de crear:

  • ¿AuthorizationLevel.Function o AuthorizationLevel.Anonymous? Depende del endpoint
  • ¿El Route coincide con la convención del proyecto?
  • ¿Se usa HttpResponseData o IActionResult?

WEBAPP — ASP.NET Core Controller

Patrón similar pero con Controller base:

[ApiController]
[Route("api/v1/[controller]")]
public class {Nombre}Controller : ControllerBase
{
    private readonly I{Nombre}Service _{campo};

    public {Nombre}Controller(I{Nombre}Service {campo}) => _{campo} = {campo};

    [HttpPost("{ruta}")]
    public async Task<ActionResult<{Nombre}Response>> PostAsync({Nombre}Request request)
    {
        var result = await _{campo}.ExecuteAsync(request);
        return Ok(result);
    }
}

Resumen ejecutivo

  1. Validar estructura del proyecto (FASE 0)
  2. Recopilar requisitos y clasificar (FASE 1)
  3. Reutilizar antes de crear (FASE 1.5)
  4. Configurar solo si es necesario (FASE 1.6)
  5. No romper API existente (FASE 1.7)
  6. Testear regresión antes de tocar (FASE 1.8)
  7. Planificar y presentar al usuario (FASE 3)
  8. Ejecutar workers en orden (FASE 4)
  9. Verificar y commitear (FASE 5)

Skills relacionados