skills/backend/hexagonal-architecture/SKILL.md
# 🗄️ Skill: Arquitectura Hexagonal (Backend) ## 📋 Metadata | Atributo | Valor | |----------|-------| | **ID** | `backend-hexagonal-architecture` | | **Nivel** | 🔴 Avanzado | | **Versión** | 1.0.0 | | **Keywords** | `hexagonal`, `hexagonal-architecture`, `ports-and-adapters`, `ddd`, `domain-driven-design` | | **Referencia** | [Alistair Cockburn - Hexagonal Architecture](https://alistair.cockburn.us/hexagonal-architecture/) | ## 🔑 Keywords para Invocación Usa cualquiera de estos keywords e
npx skillsauth add altrupets/monorepo skills/backend/hexagonal-architectureInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
| Atributo | Valor |
|----------|-------|
| ID | backend-hexagonal-architecture |
| Nivel | 🔴 Avanzado |
| Versión | 1.0.0 |
| Keywords | hexagonal, hexagonal-architecture, ports-and-adapters, ddd, domain-driven-design |
| Referencia | Alistair Cockburn - Hexagonal Architecture |
Usa cualquiera de estos keywords en tus prompts para invocar este skill:
hexagonalhexagonal-architectureports-and-adaptersbackend-hexagonal@skill:hexagonalCrea un microservicio usando arquitectura hexagonal
Implementa un caso de uso siguiendo el patrón ports and adapters
@skill:hexagonal - Estructura el módulo de usuarios con arquitectura hexagonal en NestJS
La Arquitectura Hexagonal, también conocida como Ports and Adapters, es un patrón de diseño que tiene como objetivo crear sistemas desacoplados, donde la lógica de negocio central (el Dominio) esté aislada de las tecnologías externas (Bases de datos, Frameworks, APIs externas, UIs).
Esta arquitectura permite que una aplicación sea igualmente dirigida por usuarios, programas, tests automatizados o scripts, y sea desarrollada y testead aislada de sus dispositivos de runtime y bases de datos eventuales.
src/
├── modules/
│ └── users/
│ ├── domain/ # 1. Capa de Dominio (El Corazón)
│ │ ├── entities/ # Entidades de dominio (Reglas de negocio)
│ │ ├── value-objects/ # Objetos de valor (Email, Password, etc.)
│ │ ├── repositories/ # INTERFACES de repositorios (Ports de salida)
│ │ ├── services/ # Servicios de dominio (Opcional)
│ │ └── events/ # Eventos de dominio
│ │
│ ├── application/ # 2. Capa de Aplicación (Casos de Uso)
│ │ ├── use-cases/ # Casos de uso (Orquestación)
│ │ ├── dtos/ # Objetos de transferencia de datos (Entrada/Salida)
│ │ ├── mappers/ # Transformadores entre Dominio y DTOs
│ │ └── ports/ # INTERFACES de entrada (Ports de entrada)
│ │
│ ├── infrastructure/ # 3. Capa de Infraestructura (Detalles)
│ │ ├── persistence/ # Implementación de repositorios (TypeORM, Prisma, etc.)
│ │ │ ├── entities/ # Entidades de base de datos (Opcional si usas mappers)
│ │ │ └── repositories/ # Implementación real (Adapters de salida)
│ │ ├── http/ # Controladores o Resolvers (Adapters de entrada)
│ │ │ ├── controllers/
│ │ │ └── resolvers/
│ │ ├── external-services/ # Clientes para APIs externas, SendGrid, etc.
│ │ └── modules/ # NestJS Modules para inyección de dependencias
│ │
│ └── users.module.ts # Punto de entrada de NestJS
Las entidades de dominio no deben depender de TypeORM, Sequelize o cualquier otro framework.
// src/modules/users/domain/entities/user.entity.ts
export class User {
constructor(
private readonly id: string,
private name: string,
private email: string,
private isActive: boolean,
) {}
public static create(id: string, name: string, email: string): User {
// Validaciones de negocio aquí
return new User(id, name, email, true);
}
public deactivate(): void {
this.isActive = false;
}
// Getters
getId(): string { return this.id; }
getName(): string { return this.name; }
getEmail(): string { return this.email; }
getIsActive(): boolean { return this.isActive; }
}
// src/modules/users/domain/repositories/user.repository.interface.ts
// Port de Salida
export interface IUserRepository {
save(user: User): Promise<void>;
findById(id: string): Promise<User | null>;
findByEmail(email: string): Promise<User | null>;
}
Orquesta el flujo de datos desde y hacia las entidades de dominio.
// src/modules/users/application/use-cases/create-user.use-case.ts
import { Inject, Injectable } from '@nestjs/common';
import { User } from '../../domain/entities/user.entity';
import { IUserRepository } from '../../domain/repositories/user.repository.interface';
import { CreateUserDto } from '../dtos/create-user.dto';
@Injectable()
export class CreateUserUseCase {
constructor(
@Inject('IUserRepository')
private readonly userRepository: IUserRepository,
) {}
async execute(dto: CreateUserDto): Promise<void> {
const existingUser = await this.userRepository.findByEmail(dto.email);
if (existingUser) {
throw new Error('User already exists');
}
const user = User.create(
crypto.randomUUID(),
dto.name,
dto.email
);
await this.userRepository.save(user);
}
}
Implementa las interfaces (Adapters) y expone la aplicación al exterior.
// src/modules/users/infrastructure/persistence/repositories/typeorm-user.repository.ts
// Adapter de Salida
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from '../../../domain/entities/user.entity';
import { IUserRepository } from '../../../domain/repositories/user.repository.interface';
import { UserEntity } from '../entities/user.entity'; // Entidad de DB
@Injectable()
export class TypeOrmUserRepository implements IUserRepository {
constructor(
@InjectRepository(UserEntity)
private readonly repository: Repository<UserEntity>,
) {}
async save(user: User): Promise<void> {
const dbUser = new UserEntity();
dbUser.id = user.getId();
dbUser.name = user.getName();
dbUser.email = user.getEmail();
dbUser.isActive = user.getIsActive();
await this.repository.save(dbUser);
}
async findByEmail(email: string): Promise<User | null> {
const dbUser = await this.repository.findOneBy({ email });
if (!dbUser) return null;
return new User(dbUser.id, dbUser.name, dbUser.email, dbUser.isActive);
}
// ... rest of methods
}
// src/modules/users/infrastructure/http/controllers/user.controller.ts
// Adapter de Entrada
import { Controller, Post, Body } from '@nestjs/common';
import { CreateUserUseCase } from '../../../application/use-cases/create-user.use-case';
import { CreateUserDto } from '../../../application/dtos/create-user.dto';
@Controller('users')
export class UserController {
constructor(private readonly createUserUseCase: CreateUserUseCase) {}
@Post()
async create(@Body() dto: CreateUserDto) {
return await this.createUserUseCase.execute(dto);
}
}
Es crucial vincular la interfaz (Port) con la implementación (Adapter).
// src/modules/users/users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CreateUserUseCase } from './application/use-cases/create-user.use-case';
import { UserController } from './infrastructure/http/controllers/user.controller';
import { UserEntity } from './infrastructure/persistence/entities/user.entity';
import { TypeOrmUserRepository } from './infrastructure/persistence/repositories/typeorm-user.repository';
@Module({
imports: [TypeOrmModule.forFeature([UserEntity])],
controllers: [UserController],
providers: [
CreateUserUseCase,
{
provide: 'IUserRepository',
useClass: TypeOrmUserRepository,
},
],
})
export class UsersModule {}
La Arquitectura Hexagonal facilita enormemente los tests, especialmente los unitarios de lógica de negocio.
No requieren base de datos, solo mocks de las interfaces.
// test/users/application/create-user.use-case.spec.ts
describe('CreateUserUseCase', () => {
it('should create a user successfully', async () => {
const mockRepo: IUserRepository = {
save: jest.fn(),
findByEmail: jest.fn().mockResolvedValue(null),
findById: jest.fn()
};
const useCase = new CreateUserUseCase(mockRepo);
await useCase.execute({ name: 'John', email: '[email protected]' });
expect(mockRepo.save).toHaveBeenCalled();
});
});
UserEntity (DB) a User (Dominio) asegura que un cambio en la base de datos no rompa el negocio.💡 Tip: Si usas GraphQL, los Resolvers van en infrastructure/http/resolvers/ de la misma manera que los controladores REST.
development
# 🔧 Skill: Native Integration (Swift/Kotlin) ## 📋 Metadata | Atributo | Valor | |----------|-------| | **ID** | `flutter-native-integration` | | **Nivel** | 🔴 Avanzado | | **Versión** | 1.0.0 | | **Keywords** | `native-integration`, `swift`, `kotlin`, `uikit`, `android-sdk`, `native-ui` | | **Referencia** | [Flutter Platform Integration](https://docs.flutter.dev/platform-integration) | ## 🔑 Keywords para Invocación Usa cualquiera de estos keywords en tus prompts para invocar este skill:
testing
# 🎨 Skill: MVVM Pattern ## 📋 Metadata | Atributo | Valor | |----------|-------| | **ID** | `flutter-mvvm-pattern` | | **Nivel** | 🟡 Intermedio | | **Versión** | 1.0.0 | | **Keywords** | `mvvm`, `model-view-viewmodel`, `provider`, `changenotifier` | ## 🔑 Keywords para Invocación Usa cualquiera de estos keywords en tus prompts para invocar este skill: - `mvvm` - `model-view-viewmodel` - `provider` - `changenotifier` - `@skill:mvvm` ### Ejemplos de Prompts ``` Crea una app de lista de ta
development
# 🎨 Skill: Arquitectura Modular ## 📋 Metadata | Atributo | Valor | |----------|-------| | **ID** | `flutter-modular-architecture` | | **Nivel** | 🔴 Avanzado | | **Versión** | 1.0.0 | | **Keywords** | `modular`, `modular-architecture`, `module`, `multi-module` | | **Referencia** | [Flutter Modular Package](https://pub.dev/packages/flutter_modular) | ## 🔑 Keywords para Invocación Usa cualquiera de estos keywords en tus prompts para invocar este skill: - `modular` - `modular-architecture`
tools
# 📱 Skill: Mobile Testing y Debugging con Flutter MCP ## 📋 Metadata | Atributo | Valor | |----------|-------| | **ID** | `flutter-mobile-testing` | | **Nivel** | 🔴 Avanzado | | **Versión** | 1.2.0 | | **Keywords** | `mobile-testing`, `integration-test`, `flutter-mcp`, `dart-mcp`, `debugging`, `logic-analysis`, `widget-inspection`, `device-testing` | | **Referencia** | [Dart and Flutter MCP server](https://docs.flutter.dev/ai/mcp-server) \| [Mobile MCP](https://github.com/mobile-next/mobile-