# Guia de Contribucion - ERP Construccion Esta guia describe las convenciones y procesos para contribuir al proyecto. --- ## Requisitos Previos - Node.js 20 LTS - Docker y Docker Compose - PostgreSQL 15 (o usar docker-compose) - Git --- ## Setup Inicial ```bash # 1. Clonar repositorio git clone cd apps/verticales/construccion # 2. Instalar dependencias cd backend && npm install # 3. Configurar variables de entorno cp ../.env.example .env # Editar .env con credenciales locales # 4. Levantar servicios docker-compose up -d postgres redis # 5. Ejecutar migraciones (si aplica) npm run migration:run # 6. Iniciar en desarrollo npm run dev ``` --- ## Estructura de Ramas | Rama | Proposito | |------|-----------| | `main` | Produccion estable | | `develop` | Integracion de features | | `feature/*` | Nuevas funcionalidades | | `fix/*` | Correcciones de bugs | | `refactor/*` | Refactorizaciones | | `docs/*` | Documentacion | ### Flujo de Trabajo ``` 1. Crear rama desde develop git checkout develop git pull origin develop git checkout -b feature/MAI-XXX-descripcion 2. Desarrollar y hacer commits git commit -m "feat(modulo): descripcion del cambio" 3. Push y crear Pull Request git push origin feature/MAI-XXX-descripcion # Crear PR en GitHub hacia develop 4. Code Review y merge ``` --- ## Convenciones de Codigo ### Nomenclatura | Tipo | Convencion | Ejemplo | |------|------------|---------| | Archivos | kebab-case.tipo.ts | `concepto.entity.ts` | | Clases | PascalCase + sufijo | `ConceptoService` | | Interfaces | PascalCase + prefijo I | `IConceptoRepository` | | Variables | camelCase | `totalAmount` | | Constantes | UPPER_SNAKE_CASE | `DB_SCHEMAS` | | Metodos | camelCase + verbo | `findByContrato` | | Enums | PascalCase | `EstimacionStatus` | | Tablas DB | snake_case plural | `presupuestos` | | Columnas DB | snake_case | `tenant_id` | ### Estructura de Archivos por Modulo ``` modules/ └── nombre-modulo/ ├── entities/ │ └── entidad.entity.ts ├── services/ │ └── entidad.service.ts ├── controllers/ │ └── entidad.controller.ts ├── dto/ │ └── entidad.dto.ts └── index.ts ``` ### Patron Entity ```typescript import { Entity, Column, PrimaryGeneratedColumn, Index } from 'typeorm'; import { DB_SCHEMAS, DB_TABLES } from '@shared/constants'; @Entity({ schema: DB_SCHEMAS.CONSTRUCTION, name: DB_TABLES.construction.CONCEPTOS, }) @Index(['tenantId', 'code'], { unique: true }) export class Concepto { @PrimaryGeneratedColumn('uuid') id: string; @Column({ name: 'tenant_id', type: 'uuid' }) tenantId: string; @Column({ name: 'code', length: 20 }) code: string; // Usar snake_case en name: para mapear a DB @Column({ name: 'created_at', type: 'timestamptz', default: () => 'NOW()' }) createdAt: Date; @Column({ name: 'deleted_at', type: 'timestamptz', nullable: true }) deletedAt: Date | null; } ``` ### Patron Service ```typescript import { Repository } from 'typeorm'; import { BaseService, ServiceContext } from '@shared/services/base.service'; import { Concepto } from '../entities/concepto.entity'; export class ConceptoService extends BaseService { constructor(repository: Repository) { super(repository); } // Metodos especificos del dominio async findByCode(ctx: ServiceContext, code: string): Promise { return this.findOne(ctx, { code }); } } ``` ### Patron DTO ```typescript import { IsString, IsOptional, IsUUID, MinLength, MaxLength } from 'class-validator'; export class CreateConceptoDto { @IsString() @MinLength(1) @MaxLength(20) code: string; @IsString() @MinLength(1) @MaxLength(200) name: string; @IsOptional() @IsUUID() parentId?: string; } export class UpdateConceptoDto { @IsOptional() @IsString() @MaxLength(200) name?: string; @IsOptional() @IsNumber() unitPrice?: number; } ``` --- ## SSOT - Constantes Centralizadas ### Regla Principal **NUNCA** hardcodear: - Nombres de schemas - Nombres de tablas - Rutas de API - Valores de enums ### Uso Correcto ```typescript // INCORRECTO @Entity({ schema: 'construction', name: 'conceptos' }) // CORRECTO import { DB_SCHEMAS, DB_TABLES } from '@shared/constants'; @Entity({ schema: DB_SCHEMAS.CONSTRUCTION, name: DB_TABLES.construction.CONCEPTOS, }) ``` ### Validacion Automatica ```bash # Detecta hardcoding de constantes npm run validate:constants # Se ejecuta en pre-commit y CI ``` --- ## Commits ### Formato de Mensaje ``` tipo(alcance): descripcion breve [cuerpo opcional] [footer opcional] ``` ### Tipos de Commit | Tipo | Descripcion | |------|-------------| | `feat` | Nueva funcionalidad | | `fix` | Correccion de bug | | `refactor` | Refactorizacion sin cambio funcional | | `docs` | Documentacion | | `test` | Tests | | `chore` | Mantenimiento, dependencias | | `style` | Formato, sin cambio de logica | | `perf` | Mejora de performance | ### Ejemplos ```bash # Feature git commit -m "feat(budgets): agregar versionamiento de presupuestos" # Fix git commit -m "fix(estimates): corregir calculo de totales con decimales" # Refactor git commit -m "refactor(auth): simplificar validacion de tokens" # Docs git commit -m "docs(api): actualizar especificacion OpenAPI" ``` --- ## Testing ### Ejecutar Tests ```bash # Todos los tests npm test # Con cobertura npm run test:coverage # Watch mode npm run test:watch # Archivo especifico npm test -- concepto.service.spec.ts ``` ### Estructura de Test ```typescript describe('ConceptoService', () => { let service: ConceptoService; let mockRepo: jest.Mocked>; const ctx: ServiceContext = { tenantId: 'test-tenant-uuid', userId: 'test-user-uuid', }; beforeEach(() => { mockRepo = createMockRepository(); service = new ConceptoService(mockRepo); }); describe('createConcepto', () => { it('should create concepto with level 0 for root', async () => { // Arrange const dto = { code: '001', name: 'Test' }; mockRepo.save.mockResolvedValue({ id: 'uuid', ...dto, level: 0 }); // Act const result = await service.createConcepto(ctx, dto); // Assert expect(result.level).toBe(0); }); it('should throw on duplicate code', async () => { // ... }); }); }); ``` ### Cobertura Minima - Statements: 80% - Branches: 75% - Functions: 80% - Lines: 80% --- ## Linting y Formato ### Ejecutar Linting ```bash # Verificar errores npm run lint # Corregir automaticamente npm run lint:fix ``` ### Configuracion ESLint El proyecto usa ESLint con TypeScript. Reglas principales: - No `any` implicito - No variables no usadas - Imports ordenados - Espacios consistentes ### Pre-commit Hook Se ejecuta automaticamente: ```bash npm run precommit # lint + validate:constants ``` --- ## Pull Requests ### Checklist Antes de crear un PR, verificar: - [ ] Tests pasan: `npm test` - [ ] Linting pasa: `npm run lint` - [ ] Constantes validadas: `npm run validate:constants` - [ ] Build funciona: `npm run build` - [ ] Documentacion actualizada (si aplica) - [ ] Commits con formato correcto ### Template de PR ```markdown ## Descripcion Breve descripcion del cambio. ## Tipo de Cambio - [ ] Feature - [ ] Bug fix - [ ] Refactor - [ ] Docs - [ ] Tests ## Modulo Afectado - MAI-XXX: Nombre del modulo ## Testing Describir como probar los cambios. ## Screenshots (si aplica) ## Checklist - [ ] Tests agregados/actualizados - [ ] Documentacion actualizada - [ ] Sin breaking changes (o documentados) ``` --- ## Migraciones de Base de Datos ### Generar Migracion ```bash # Despues de modificar entidades npm run migration:generate -- -n NombreDescriptivo ``` ### Ejecutar Migraciones ```bash # Aplicar pendientes npm run migration:run # Revertir ultima npm run migration:revert ``` ### Convenciones - Una migracion por feature/fix - Nombres descriptivos: `AddStatusToEstimaciones` - Incluir rollback funcional - No modificar migraciones ya aplicadas en produccion --- ## Debugging ### VS Code ```json // .vscode/launch.json { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug Backend", "runtimeArgs": ["-r", "ts-node/register"], "args": ["${workspaceFolder}/backend/src/server.ts"], "env": { "NODE_ENV": "development", "LOG_LEVEL": "debug" } } ] } ``` ### Variables de Entorno para Debug ```bash LOG_LEVEL=debug TYPEORM_LOGGING=true ``` --- ## Contacto - **Issues:** Reportar bugs o sugerir features en GitHub Issues - **PRs:** Siempre bienvenidos, seguir las convenciones --- **Ultima actualizacion:** 2025-12-12