feat: FluxAI multi-step autonomy + rate limiting + image pipeline
Deploy to VPS / deploy (push) Has been cancelled
Deploy to VPS / deploy (push) Has been cancelled
Two production-grade hardening additions and one cost optimisation. FLUXAI AUTONOMY RESTORED (api/chat) - Brings back the multi-step agentic flow that the system prompt was always designed for. The "temporarily removed maxSteps" comment is gone — replaced with the AI SDK 6 equivalent stopWhen: stepCountIs(5). - Cap at 5 chained tool calls per turn bounds latency + LLM cost. - maxDuration raised 30s → 60s to absorb tool-chain runs. - Result: one user prompt now triggers, e.g. search_installations → energy_savings_calculator → show_case_study → schedule_consultation in a single turn — exactly the SPIN methodology in the prompt. RATE LIMITING (src/lib/rateLimit.ts + api/chat) - Token-bucket per IP: 30 messages burst, sustained 30/minute. Trips to 429 with Retry-After + X-RateLimit-Remaining headers when abused. - IP extracted from x-forwarded-for (Nginx already passes this). - In-memory Map with 10-min GC of stale buckets — no Redis dep. If we scale to multiple replicas later, swap the Map for Upstash. - Protects the OpenAI quota from someone hammering the chat endpoint. IMAGE PIPELINE (src/lib/imageOptimizer.ts) - sharp-based optimizer: auto-orient (EXIF), cap at 2560px long side, re-encode WebP@85, content-hash filename. Re-uploads with same content reuse the same hash; new content gets a new URL — perfect cache invalidation without header tricks. - Opt-in via optimize=1 form/query param on /api/assets POST. - Hero CMS and Site Settings uploads turn it on automatically (those are user-facing brand assets where compression matters most). - App/news/parts uploads remain untouched (editors may be uploading CAD drawings, datasheets, etc. that shouldn't be transcoded). - Falls back gracefully to a no-op for unsupported formats (SVG, GIF, videos, anything sharp can't decode) so it never breaks an upload. DOCKERFILE - Adds vips/vips-dev for sharp on Alpine + --include=optional so the @img/sharp-linuxmusl-x64 prebuilt is downloaded - Explicitly copies node_modules/sharp + node_modules/@img to the runner stage (Next.js trace can miss conditional deps). NO DB SCHEMA CHANGES.
This commit is contained in:
+15
-2
@@ -5,11 +5,15 @@
|
||||
|
||||
# ── Stage 1: Install dependencies ──
|
||||
FROM node:22-alpine AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
# libc6-compat: glibc shim for prebuilt native binaries (Prisma engines)
|
||||
# vips-dev: required for sharp on Alpine — image processing native lib
|
||||
RUN apk add --no-cache libc6-compat vips-dev
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
# --include=optional ensures @img/sharp-linuxmusl-x64 (the Alpine sharp
|
||||
# prebuilt binary) is downloaded; otherwise sharp errors at runtime.
|
||||
RUN npm ci --include=optional
|
||||
|
||||
# ── Stage 2: Build the application ──
|
||||
FROM node:22-alpine AS builder
|
||||
@@ -36,6 +40,9 @@ WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# vips runtime — required for sharp at runtime, not just build
|
||||
RUN apk add --no-cache vips
|
||||
|
||||
# Security: run as non-root user
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
@@ -52,6 +59,12 @@ COPY --from=builder /app/prisma ./prisma
|
||||
COPY --from=builder /app/node_modules/.prisma ./node_modules/.prisma
|
||||
COPY --from=builder /app/node_modules/@prisma ./node_modules/@prisma
|
||||
|
||||
# Copy sharp binary explicitly — Next.js standalone trace usually picks it
|
||||
# up, but the @img/sharp-linuxmusl-x64 prebuilt is platform-conditional and
|
||||
# can be missed. Copying both directories guarantees runtime availability.
|
||||
COPY --from=builder /app/node_modules/sharp ./node_modules/sharp
|
||||
COPY --from=builder /app/node_modules/@img ./node_modules/@img
|
||||
|
||||
# Copy i18n message files (required by next-intl at runtime)
|
||||
COPY --from=builder /app/messages ./messages
|
||||
|
||||
|
||||
Reference in New Issue
Block a user