SAT sync enhancements:
- Filter active (vigente) CFDIs only via DocumentStatus to avoid SAT
rejecting recibidos with "No se permite descarga de XML cancelados"
- Reclassify CFDIs at save time: tipo='ingreso' received by tenant
becomes 'egreso' based on RFC (emisor vs receptor)
- Fix pool cleanup bug during long syncs: refresh getPool() on each
saveCfdis call instead of holding stale reference for 45+ minutes
- Add X-View-Tenant support to SAT controller via viewingTenantId
- Add tenantMiddleware to SAT routes for global admin impersonation
Cron jobs:
- Add separate every-6-hours schedule for specific RFCs
- ROEM691011EZ4 configured for frequent sync (00, 06, 12, 18 MX time)
XML filesystem export:
- Write .xml files to /var/horux/xml/<RFC>/YYYY/MM/UUID.xml
- Activated per-RFC via XML_EXPORT_RFCS allowlist
- Organized by year/month for browsability
Auth improvements:
- Send welcome + admin-notification emails on /auth/register
(previously only /tenants createTenant flow sent emails)
- Set role='contador' for self-registered users (not admin) to prevent
new tenants from accessing cross-tenant data
Infrastructure:
- Set express trust proxy=1 to accept X-Forwarded-For from Nginx
(fixes ERR_ERL_UNEXPECTED_X_FORWARDED_FOR from rate limiter)
Operational scripts:
- setup-horux360-tenant.ts: Provision Horux 360 tenant manually
- send-welcome-aaron.ts: Resend welcome email for Aaron (registered
before welcome-on-register was added)
- export-xmls-roem.ts: Backfill filesystem XMLs from DB for ROEM
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CRITICAL fixes:
- Restrict X-View-Tenant impersonation to global admin only (was any admin)
- Add authorization to subscription endpoints (was open to any user)
- Make webhook signature verification mandatory (was skippable)
- Remove databaseName from JWT payload (resolve server-side with cache)
- Reduce body size limit from 1GB to 10MB (50MB for bulk CFDI)
- Restrict .env file permissions to 600
HIGH fixes:
- Add authorization to SAT cron endpoints (global admin only)
- Add Content-Security-Policy and Permissions-Policy headers
- Centralize isGlobalAdmin() utility with caching
- Add rate limiting on auth endpoints (express-rate-limit)
- Require authentication on logout endpoint
MEDIUM fixes:
- Replace Math.random() with crypto.randomBytes for temp passwords
- Remove console.log of temporary passwords in production
- Remove DB credentials from admin notification email
- Add escapeHtml() to email templates (prevent HTML injection)
- Add file size validation on FIEL upload (50KB max)
- Require TLS for SMTP connections
- Normalize email to lowercase before uniqueness check
- Remove hardcoded default for FIEL_ENCRYPTION_KEY
Also includes:
- Complete production deployment documentation
- API reference documentation
- Security audit report with remediation details
- Updated README with v0.5.0 changelog
- New client admin email template
- Utility scripts (create-carlos, test-emails)
- PM2 ecosystem config updates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Decrypts .cer and .key from FIEL_STORAGE_PATH/<RFC>/ to /tmp with
30-minute auto-cleanup for security.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>