From c05e83fff53e7c3692cc8a491cfa4ba985a8dbdd Mon Sep 17 00:00:00 2001 From: Yaugourt Date: Sun, 31 May 2026 09:30:39 -0400 Subject: [PATCH] fix(infra+liquidations): harden Dockerfile and use unambiguous time_ms in liquidation ingestion - Liquidation persistence: `time: new Date(liq.time)` parsed a TZ-naive ISO string and silently interpreted it as host local time. Switch both ingestion and backfill to `new Date(liq.time_ms)` (already on the payload) to remove TZ ambiguity and protect the time-bucketed analytics. - Dockerfile: drop production root user (add `USER node` + `--chown=node:node` on COPY), drop the unused `ARG/ENV DATABASE_URL` (prisma generate does not need it), and add a HEALTHCHECK hitting `/api/health/ready`. - Add `.dockerignore` so `COPY . .` no longer ships `.git`, local `.env*`, dev tooling and logs into the production image. Co-Authored-By: Claude Opus 4.7 --- .dockerignore | 17 ++++++++ Dockerfile | 39 ++++++++++--------- .../liquidations.backfill.service.ts | 2 +- .../liquidations.ingestion.service.ts | 2 +- 4 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ea462c5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +node_modules +.git +.gitignore +.env +.env.* +dist +coverage +tests +docs +*.md +.agents +.cursor +.gemini +.github +*.log +logs.*.json* +.DS_Store diff --git a/Dockerfile b/Dockerfile index 34fba2a..0379796 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,13 @@ -# ─── Stage 1: Build ─────────────────────────────────────────────────────────── +# Stage 1: Build FROM node:20.19.0-alpine AS builder WORKDIR /app -ARG DATABASE_URL -ENV DATABASE_URL=$DATABASE_URL - -# Dépendances — layer en cache tant que package.json ne change pas +# Deps layer cached as long as package.json is unchanged COPY package*.json ./ RUN npm ci -# Schémas Prisma — layer séparé pour ne régénérer que si les schémas changent +# Prisma schemas in a dedicated layer so codegen only re-runs on schema changes COPY prisma ./prisma/ COPY prisma-historical ./prisma-historical/ COPY prisma-content ./prisma-content/ @@ -21,29 +18,33 @@ RUN npx prisma generate \ && npx prisma generate --schema ./prisma-content/schema.prisma \ && npx prisma generate --schema ./prisma-telegram/schema.prisma -# Code source + build TypeScript +# Source code + TypeScript build COPY . . RUN npm run build -# Élagage des devDeps dans le même node_modules (évite une 2e install complète) +# Prune devDeps in place to avoid a second full install RUN npm prune --omit=dev -# ─── Stage 2: Production ────────────────────────────────────────────────────── +# Stage 2: Production FROM node:20.19.0-alpine AS production WORKDIR /app -# node_modules déjà élagués + clients Prisma générés — aucune install supplémentaire -COPY --from=builder /app/node_modules ./node_modules -COPY --from=builder /app/prisma ./prisma/ -COPY --from=builder /app/prisma-historical ./prisma-historical/ -COPY --from=builder /app/prisma-content ./prisma-content/ -COPY --from=builder /app/prisma-telegram ./prisma-telegram/ -COPY --from=builder /app/prisma.config.ts ./ -COPY --from=builder /app/dist ./dist -COPY --from=builder /app/package.json ./ -COPY --from=builder /app/scripts ./scripts/ +COPY --from=builder --chown=node:node /app/node_modules ./node_modules +COPY --from=builder --chown=node:node /app/prisma ./prisma/ +COPY --from=builder --chown=node:node /app/prisma-historical ./prisma-historical/ +COPY --from=builder --chown=node:node /app/prisma-content ./prisma-content/ +COPY --from=builder --chown=node:node /app/prisma-telegram ./prisma-telegram/ +COPY --from=builder --chown=node:node /app/prisma.config.ts ./ +COPY --from=builder --chown=node:node /app/dist ./dist +COPY --from=builder --chown=node:node /app/package.json ./ +COPY --from=builder --chown=node:node /app/scripts ./scripts/ + +USER node EXPOSE 3002 +HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ + CMD wget -qO- http://127.0.0.1:3002/api/health/ready || exit 1 + CMD ["node", "dist/app.js"] diff --git a/src/services/liquidations/liquidations.backfill.service.ts b/src/services/liquidations/liquidations.backfill.service.ts index b6ceb37..8d018a7 100644 --- a/src/services/liquidations/liquidations.backfill.service.ts +++ b/src/services/liquidations/liquidations.backfill.service.ts @@ -114,7 +114,7 @@ export class LiquidationsBackfillService { private toCreateInput(liq: Liquidation): RawLiquidationCreateInput { return { tid: BigInt(liq.tid), - time: new Date(liq.time), + time: new Date(liq.time_ms), timeMs: BigInt(liq.time_ms), coin: liq.coin, hash: liq.hash, diff --git a/src/services/liquidations/liquidations.ingestion.service.ts b/src/services/liquidations/liquidations.ingestion.service.ts index a322074..02bb780 100644 --- a/src/services/liquidations/liquidations.ingestion.service.ts +++ b/src/services/liquidations/liquidations.ingestion.service.ts @@ -166,7 +166,7 @@ export class LiquidationsIngestionService { private toCreateInput(liq: Liquidation): RawLiquidationCreateInput { return { tid: BigInt(liq.tid), - time: new Date(liq.time), + time: new Date(liq.time_ms), timeMs: BigInt(liq.time_ms), coin: liq.coin, hash: liq.hash,