8.6 KiB
8.6 KiB
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
# 1. Clonar repositorio
git clone <repo-url>
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
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
import { Repository } from 'typeorm';
import { BaseService, ServiceContext } from '@shared/services/base.service';
import { Concepto } from '../entities/concepto.entity';
export class ConceptoService extends BaseService<Concepto> {
constructor(repository: Repository<Concepto>) {
super(repository);
}
// Metodos especificos del dominio
async findByCode(ctx: ServiceContext, code: string): Promise<Concepto | null> {
return this.findOne(ctx, { code });
}
}
Patron DTO
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
// 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
# 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
# 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
# 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
describe('ConceptoService', () => {
let service: ConceptoService;
let mockRepo: jest.Mocked<Repository<Concepto>>;
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
# Verificar errores
npm run lint
# Corregir automaticamente
npm run lint:fix
Configuracion ESLint
El proyecto usa ESLint con TypeScript. Reglas principales:
- No
anyimplicito - No variables no usadas
- Imports ordenados
- Espacios consistentes
Pre-commit Hook
Se ejecuta automaticamente:
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
## 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
# Despues de modificar entidades
npm run migration:generate -- -n NombreDescriptivo
Ejecutar Migraciones
# 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
// .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
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