Convenciones de código, naming y TypeScript para el proyecto de facturación. Leer antes de generar cualquier código para asegurar consistencia en naming, estructura de respuestas API, TypeScript strict y reglas de seguridad del proyecto.
"strict": true en tsconfig.jsonany: tipar explícitamente siempreI — IFactura, IReceptorFacturaStatus, MetodoPagoexport const METODO_PAGO = {
PUE: 'PUE',
PPD: 'PPD',
} as const
export type MetodoPago = typeof METODO_PAGO[keyof typeof METODO_PAGO]
| Elemento | Convención | Ejemplo |
|---|---|---|
| Componentes React | PascalCase |
FacturaTable, EmisorCard |
| Hooks | camelCase con use | useFacturas, useReceptor |
| Constantes | UPPER_SNAKE_CASE | MAX_EMISORES, DEFAULT_IVA |
| Funciones utilitarias | camelCase | formatMonto, parseCFDI |
| Archivos de componente | kebab-case | factura-table.tsx |
| API Routes | kebab-case | /api/v1/facturas/[id]/reenviar |
| Comentarios | En español | // Recupera la API Key del RFC emisor |
Base: /api/v1/
/api/v1/facturas GET (listado) | POST (crear)
/api/v1/facturas/[id] GET (detalle)
/api/v1/facturas/[id]/reenviar POST (reenviar correo)
/api/v1/emisores GET | POST
/api/v1/receptores GET | POST
/api/v1/conceptos GET | POST
/api/v1/fiscal/extract POST (extraer datos de PDF constancia)
/api/v1/pagos GET | POST (complementos de pago)
return NextResponse.json({
success: true,
data: { ... },
meta: { total: 100, page: 1 } // solo en listados
})
return NextResponse.json({
success: false,
error: {
code: 'RECEPTOR_NOT_FOUND',
message: 'No se encontró el receptor con RFC proporcionado'
}
}, { status: 404 })
export const ERROR_CODES = {
// Genéricos
VALIDATION_ERROR: 'VALIDATION_ERROR',
UNAUTHORIZED: 'UNAUTHORIZED',
NOT_FOUND: 'NOT_FOUND',
// Facturación
RECEPTOR_NOT_FOUND: 'RECEPTOR_NOT_FOUND',
EMISOR_NOT_FOUND: 'EMISOR_NOT_FOUND',
CONCEPTO_NOT_FOUND: 'CONCEPTO_NOT_FOUND',
TIMBRADO_ERROR: 'TIMBRADO_ERROR',
FOLIO_INSUFICIENTE: 'FOLIO_INSUFICIENTE',
CFDI_INVALIDO: 'CFDI_INVALIDO',
// Storage
UPLOAD_ERROR: 'UPLOAD_ERROR',
// Claude
EXTRACTION_ERROR: 'EXTRACTION_ERROR',
} as const
.env.local para desarrollo (en .gitignore).env.example (sin valores reales) en el repoNEXT_PUBLIC_ para claves sensibles (service role, API Keys).env// ❌ NUNCA
const data: any = await fetch(...)
const API_KEY = "sk-abc123..."
console.log("Debug:", data) // en producción
<button onClick={() => { fetch(...) }}> // lógica en componente
// ✅ SIEMPRE
const data: IFactura = await fetch(...)
const apiKey = process.env.ANTHROPIC_API_KEY!
// (sin console.log en producción — usar logger si se necesita)
// Lógica de negocio en /lib o API Routes, no en componentes
| Branch | Uso |
|---|---|
main | Producción — protegido, requiere PR |
staging | Pre-producción — pruebas antes de merge |
develop | Base de trabajo diario |
feature/nombre | Desde develop |
fix/nombre | Desde develop o main |
any en TypeScriptconsole.log sin comentario de debug