- 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>
9.6 KiB
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