platform-marketing-content/docs/95-guias-desarrollo/GUIA-CONVENCIONES.md
rckrdmrd 74b5ed7f38 feat: Complete documentation update and orchestration configuration
- Update vision, architecture and technical documentation
- Update module definitions (PMC-001 to PMC-008)
- Update requirements documentation
- Add CONTEXT-MAP.yml and ENVIRONMENT-INVENTORY.yml
- Add orchestration guidelines and references

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:38:31 -06:00

9.6 KiB

id title type status project version created_date updated_date
GUIA-CONVENCIONES Guía de Convenciones de Desarrollo Guide Active platform_marketing_content 1.0.0 2026-01-04 2026-01-04

Guía de Convenciones de Desarrollo

Versión: 1.0.0 Fecha: 2025-12-08 Proyecto: Platform Marketing Content


Estructura del Proyecto

platform_marketing_content/
├── apps/
│   ├── backend/                 # API NestJS
│   │   ├── src/
│   │   │   ├── modules/         # Módulos por dominio
│   │   │   │   ├── auth/
│   │   │   │   ├── crm/
│   │   │   │   ├── projects/
│   │   │   │   ├── generation/
│   │   │   │   ├── assets/
│   │   │   │   ├── automation/
│   │   │   │   └── analytics/
│   │   │   ├── common/          # Utilidades compartidas
│   │   │   ├── config/          # Configuración
│   │   │   └── main.ts
│   │   ├── test/
│   │   └── package.json
│   │
│   ├── frontend/                # React + Vite
│   │   ├── src/
│   │   │   ├── components/      # Componentes reutilizables
│   │   │   ├── pages/           # Páginas/vistas
│   │   │   ├── hooks/           # Custom hooks
│   │   │   ├── services/        # API clients
│   │   │   ├── stores/          # Estado global
│   │   │   └── utils/           # Utilidades
│   │   └── package.json
│   │
│   └── comfyui/                 # Workflows ComfyUI
│       └── workflows/
│
├── docs/                        # Documentación
├── orchestration/               # Config SIMCO
└── docker-compose.yml

Convenciones de Nomenclatura

Backend (NestJS/TypeScript)

// Archivos: kebab-case
user.controller.ts
create-user.dto.ts
user.service.ts
user.entity.ts

// Clases: PascalCase
export class UserService {}
export class CreateUserDto {}

// Interfaces: PascalCase con prefijo I opcional
export interface IUserRepository {}
export interface User {}

// Variables y funciones: camelCase
const userId = '...';
function getUserById() {}

// Constantes: UPPER_SNAKE_CASE
const MAX_RETRY_ATTEMPTS = 3;
const DEFAULT_PAGE_SIZE = 20;

// Enums: PascalCase
enum UserStatus {
  ACTIVE = 'active',
  SUSPENDED = 'suspended',
}

Frontend (React/TypeScript)

// Componentes: PascalCase
UserProfile.tsx
AssetCard.tsx

// Hooks: camelCase con prefijo use
useAuth.ts
useAssets.ts

// Stores: camelCase
authStore.ts
assetsStore.ts

// Utilidades: camelCase
formatDate.ts
validateEmail.ts

Base de Datos

-- Tablas: snake_case, plural
CREATE TABLE users ...
CREATE TABLE generation_jobs ...

-- Columnas: snake_case
user_id
created_at
is_active

-- Índices: idx_{tabla}_{columnas}
idx_users_email
idx_jobs_tenant_status

-- Foreign keys: fk_{tabla}_{referencia}
fk_users_tenant

Estructura de Módulos Backend

modules/crm/
├── controllers/
│   ├── clients.controller.ts
│   ├── brands.controller.ts
│   └── products.controller.ts
├── services/
│   ├── clients.service.ts
│   ├── brands.service.ts
│   └── products.service.ts
├── entities/
│   ├── client.entity.ts
│   ├── brand.entity.ts
│   └── product.entity.ts
├── dto/
│   ├── create-client.dto.ts
│   ├── update-client.dto.ts
│   └── client-response.dto.ts
├── repositories/
│   └── clients.repository.ts
├── crm.module.ts
└── index.ts

Patrones de Código

Controllers

@Controller('crm/clients')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiTags('CRM - Clients')
export class ClientsController {
  constructor(private readonly clientsService: ClientsService) {}

  @Post()
  @ApiOperation({ summary: 'Create a new client' })
  @ApiResponse({ status: 201, type: ClientResponseDto })
  async create(
    @CurrentTenant() tenantId: string,
    @Body() createClientDto: CreateClientDto,
  ): Promise<ClientResponseDto> {
    return this.clientsService.create(tenantId, createClientDto);
  }

  @Get()
  @ApiOperation({ summary: 'List all clients' })
  async findAll(
    @CurrentTenant() tenantId: string,
    @Query() query: ListClientsQueryDto,
  ): Promise<PaginatedResponse<ClientResponseDto>> {
    return this.clientsService.findAll(tenantId, query);
  }
}

Services

@Injectable()
export class ClientsService {
  constructor(
    private readonly clientsRepository: ClientsRepository,
    private readonly eventEmitter: EventEmitter2,
  ) {}

  async create(tenantId: string, dto: CreateClientDto): Promise<Client> {
    const client = await this.clientsRepository.create({
      ...dto,
      tenantId,
      status: ClientStatus.PROSPECT,
    });

    this.eventEmitter.emit('client.created', { client });

    return client;
  }

  async findAll(tenantId: string, query: ListClientsQueryDto): Promise<PaginatedResponse<Client>> {
    return this.clientsRepository.findAllPaginated(tenantId, query);
  }
}

DTOs

export class CreateClientDto {
  @ApiProperty({ example: 'Acme Corp' })
  @IsString()
  @MinLength(2)
  @MaxLength(255)
  name: string;

  @ApiPropertyOptional()
  @IsString()
  @IsOptional()
  legalName?: string;

  @ApiPropertyOptional({ enum: ClientSize })
  @IsEnum(ClientSize)
  @IsOptional()
  size?: ClientSize;
}

Entities

@Entity('clients', { schema: 'crm' })
export class Client extends BaseEntity {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column('uuid')
  tenantId: string;

  @Column({ length: 255 })
  name: string;

  @Column({ type: 'enum', enum: ClientStatus, default: ClientStatus.PROSPECT })
  status: ClientStatus;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @OneToMany(() => Brand, (brand) => brand.client)
  brands: Brand[];
}

API Response Format

Success Response

{
  "data": { ... },
  "meta": {
    "timestamp": "2025-12-08T10:30:00Z"
  }
}

Paginated Response

{
  "data": [...],
  "meta": {
    "total": 100,
    "page": 1,
    "limit": 20,
    "totalPages": 5
  }
}

Error Response

{
  "statusCode": 400,
  "message": "Validation failed",
  "errors": [
    {
      "field": "email",
      "message": "Invalid email format"
    }
  ],
  "timestamp": "2025-12-08T10:30:00Z"
}

Git Workflow

Branches

main                    # Producción
├── develop             # Desarrollo
│   ├── feature/PMC-001-tenants
│   ├── feature/PMC-002-crm
│   ├── fix/login-validation
│   └── refactor/auth-middleware

Commit Messages

feat(crm): add client creation endpoint
fix(auth): resolve token refresh issue
docs(api): update swagger documentation
refactor(generation): extract queue service
test(assets): add upload unit tests
chore(deps): update dependencies

Pull Request Template

## Description
Brief description of changes

## Type of Change
- [ ] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation

## Testing
- [ ] Unit tests added/updated
- [ ] Manual testing completed

## Checklist
- [ ] Code follows conventions
- [ ] Self-review completed
- [ ] Documentation updated

Testing

Unit Tests

describe('ClientsService', () => {
  let service: ClientsService;
  let repository: MockType<ClientsRepository>;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        ClientsService,
        { provide: ClientsRepository, useFactory: mockRepository },
      ],
    }).compile();

    service = module.get(ClientsService);
    repository = module.get(ClientsRepository);
  });

  describe('create', () => {
    it('should create a client with prospect status', async () => {
      const dto = { name: 'Test Client' };
      repository.create.mockResolvedValue({ id: '1', ...dto, status: 'prospect' });

      const result = await service.create('tenant-1', dto);

      expect(result.status).toBe('prospect');
      expect(repository.create).toHaveBeenCalledWith(expect.objectContaining({
        tenantId: 'tenant-1',
      }));
    });
  });
});

E2E Tests

describe('Clients (e2e)', () => {
  let app: INestApplication;

  beforeAll(async () => {
    app = await createTestApp();
  });

  it('/crm/clients (POST)', () => {
    return request(app.getHttpServer())
      .post('/crm/clients')
      .set('Authorization', `Bearer ${token}`)
      .send({ name: 'Test Client' })
      .expect(201)
      .expect((res) => {
        expect(res.body.data.name).toBe('Test Client');
      });
  });
});

Environment Variables

# .env.example

# App
NODE_ENV=development
PORT=3000
API_PREFIX=api/v1

# Database
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=pmc
DATABASE_USER=pmc_user
DATABASE_PASSWORD=secret

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379

# JWT
JWT_SECRET=your-secret-key
JWT_EXPIRES_IN=1d

# Storage
S3_ENDPOINT=http://localhost:9000
S3_ACCESS_KEY=minioadmin
S3_SECRET_KEY=minioadmin
S3_BUCKET=pmc-assets

# ComfyUI
COMFYUI_URL=http://localhost:8188
COMFYUI_WEBHOOK_SECRET=webhook-secret

# OpenAI (for text generation)
OPENAI_API_KEY=sk-...

Referencias


Documento generado por: Requirements-Analyst Fecha: 2025-12-08