Integrations
The backend integrates with several external or cross-cutting systems, but Redis is intentionally used only above the database boundary (token revocation, throttling, queues). PostgreSQL remains the single source of truth.
src/redis/redis.module.ts provides a REDIS_CLIENT token and a TokenStore abstraction.
export const REDIS_CLIENT = 'SIM_REDIS_CLIENT';
@Global()@Module({ providers: [ { provide: REDIS_CLIENT, useFactory: (config) => new Redis(REDIS_URL) || null }, { provide: TokenStore, useFactory: (_, client) => client ? new RedisTokenStore(client) : new InMemoryTokenStore() }, ], exports: [TokenStore, REDIS_CLIENT],})- In development,
REDIS_URLabsent falls back toInMemoryTokenStore. - In production,
REDIS_URLis required.
Token store
Section titled “Token store”- Keys:
sim:auth:jti:${jti}withEXTTL. revokedfails open on Redis outage.- Used by
JwtAuthGuardto deny revoked access tokens.
Other Redis consumers
Section titled “Other Redis consumers”src/jobs/jobs.queue.ts— BullMQQueuesrc/jobs/jobs.worker.ts— BullMQWorkersrc/health/indicators.ts— Redis health ping
S3 / MinIO
Section titled “S3 / MinIO”src/s3/s3.module.ts exports a global S3_CLIENT provider.
export const S3_CLIENT = 'SIM_S3_CLIENT';
new S3Client({ endpoint: s3.endpoint, region: s3.region, forcePathStyle: true, // required for MinIO credentials: { accessKeyId, secretAccessKey },});Local defaults
Section titled “Local defaults”export const S3_DEFAULTS = { endpoint: 'http://127.0.0.1:9000', region: 'us-east-1', bucket: 'sim', accessKeyId: 'sim', secretAccessKey: 'sim-admin',};Uploads
Section titled “Uploads”src/uploads/uploads.service.ts:
- validates category and MIME type
- generates
<categorie>/<userId>-<uuid>.<ext> - auto-creates bucket if missing
- returns object bytes for
GET /api/v1/uploads?key=... - validates
KEY_PATTERNbeforeGetObjectto prevent path traversal
Object keys are stored in PostgreSQL; only the key, not the file content, lives in the database.
src/mailer wraps Resend. In development, emails are logged rather than sent because RESEND_API_KEY defaults to empty. Password-reset emails are the primary user-facing email flow.
PDF / Puppeteer
Section titled “PDF / Puppeteer”src/pdf provides PdfService.render(html, filename) using headless Chromium. The Dockerfile installs Chrome libraries and sets PUPPETEER_EXECUTABLE_PATH.
PDF services per module:
src/residence/contrat-pdf.service.ts— 25-article French leasesrc/residence/echeance-pdf.service.ts— rent receiptsrc/residence/paiement-pdf.service.ts— generic resident payment receiptsrc/facturation/facture-pdf.service.ts— A4 invoice + 58/80mm ticketsrc/rh/bulletin-pdf.service.ts— payslipsrc/rapports/rapports-pdf.service.ts— report sheetssrc/audit/audit-pdf.service.ts— audit journal reportsrc/dashboard/dashboard-pdf.service.ts— dashboard tiles
Pure SVG chart generation lives in src/audit/audit-charts.ts.
Prometheus metrics
Section titled “Prometheus metrics”src/metrics exposes GET /metrics as a public, version-neutral scrape endpoint.
MetricsMiddleware records:
http_requests_total{method, route, status}http_request_duration_seconds{method, route, status}
Additional counters:
sim_jobs_total{job, outcome}sim_jobs_queue_depth{status}
Default Node metrics are disabled under NODE_ENV=test.
BullMQ jobs
Section titled “BullMQ jobs”src/jobs/jobs.queue.ts creates a bullmq Queue only when REDIS_URL is set. src/jobs/jobs.worker.ts consumes sim-jobs with concurrency: 1. Jobs are added with attempts: 3 and fixed 5-second backoff.
The service seam in src/jobs/jobs.service.ts wraps each job with metrics logging and rethrows errors so HTTP triggers surface real failures.
Health checks
Section titled “Health checks”src/health exposes public routes:
| Route | Purpose |
|---|---|
/api/v1/health/live |
Always { status: 'ok' } |
/api/v1/health/ready |
PostgreSQL + Redis readiness |
/api/v1/health |
Aggregate |
PgHealthIndicator runs select 1 on the real Kysely instance. RedisHealthIndicator pings ioredis or reports mode: 'in-memory' when Redis is absent.