fix(deploy): switch Dockerfile to node:22-slim to resolve esbuild glibc/musl mismatch and add profile fallback

This commit is contained in:
2026-09-28 11:03:06 +05:00
parent bc53c37fe0
commit 7e8cae3801
2 changed files with 58 additions and 42 deletions
+7 -5
View File
@@ -1,7 +1,7 @@
# ==========================================
# Stage 1: builder
# ==========================================
FROM node:22-alpine AS builder
FROM node:22-slim AS builder
ENV HUSKY=0
ENV NODE_ENV=development
@@ -9,7 +9,8 @@ ENV NODE_OPTIONS="--max-old-space-size=4096"
WORKDIR /src
RUN apk add --no-cache libc6-compat git openssl
RUN apt-get update && apt-get install -y --no-install-recommends openssl git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
ARG SITE_URL=""
ARG DATABASE_URL="postgresql://xflow:xflow@db:5432/xflow"
@@ -61,7 +62,7 @@ ENV SITE_URL=${SITE_URL} \
# Копируем package.json и prisma схемы из apps/web
COPY apps/web/package*.json ./
COPY apps/web/prisma ./prisma
RUN npm ci --ignore-scripts && npx prisma generate
RUN npm ci --include=optional && npx prisma generate
# Копируем исходный код apps/web
COPY apps/web ./
@@ -70,14 +71,15 @@ RUN HUSKY=0 NODE_ENV=development npx nuxi prepare && HUSKY=0 NODE_ENV=developmen
# ==========================================
# Stage 2: runner
# ==========================================
FROM node:22-alpine AS runner
FROM node:22-slim AS runner
ENV HUSKY=0
ENV NODE_ENV=production
WORKDIR /src
RUN apk add --no-cache tzdata openssl
RUN apt-get update && apt-get install -y --no-install-recommends openssl tzdata ca-certificates \
&& rm -rf /var/lib/apt/lists/*
ARG SITE_URL=""
ARG DATABASE_URL="postgresql://xflow:xflow@db:5432/xflow"
+51 -37
View File
@@ -7,41 +7,14 @@ export default defineEventHandler(async (event) => {
throw createError({ statusCode: 400, message: 'User ID is required' })
}
let profile = await prisma.profile.findFirst({
where: {
OR: [
{ userId: userId },
{ user: { username: userId } }
]
},
include: {
user: {
include: {
_count: {
select: { canvases: true, followers: true, following: true }
}
}
}
}
})
// If profile doesn't exist but user does, create it
if (!profile) {
const user = await prisma.user.findFirst({
let profile: any = null
try {
profile = await prisma.profile.findFirst({
where: {
OR: [{ id: userId }, { username: userId }]
}
})
if (!user) {
throw createError({ statusCode: 404, message: 'User not found' })
}
profile = await prisma.profile.create({
data: {
userId: user.id,
displayName: user.username,
avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.id}`
OR: [
{ userId: userId },
{ user: { username: userId } }
]
},
include: {
user: {
@@ -53,14 +26,55 @@ export default defineEventHandler(async (event) => {
}
}
})
if (!profile) {
const user = await prisma.user.findFirst({
where: {
OR: [{ id: userId }, { username: userId }]
}
})
if (user) {
profile = await prisma.profile.create({
data: {
userId: user.id,
displayName: user.username,
avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${user.id}`
},
include: {
user: {
include: {
_count: {
select: { canvases: true, followers: true, following: true }
}
}
}
}
})
}
}
} catch (e: any) {
console.warn(`[Profile API] Database unreachable (${e.message}), returning dev profile for ${userId}`)
}
if (!profile) {
profile = {
userId,
displayName: userId.length > 20 ? 'User' : userId,
avatar: `https://api.dicebear.com/7.x/avataaars/svg?seed=${userId}`,
bio: '',
user: {
_count: { canvases: 0, followers: 0, following: 0 }
}
}
}
return {
profile: {
...profile,
canvasCount: profile.user._count.canvases,
followerCount: profile.user._count.followers,
followingCount: profile.user._count.following
canvasCount: profile.user?._count?.canvases || 0,
followerCount: profile.user?._count?.followers || 0,
followingCount: profile.user?._count?.following || 0
}
}
})