diff --git a/Dockerfile.coolify b/Dockerfile.coolify index e4fb8f7..3d65192 100644 --- a/Dockerfile.coolify +++ b/Dockerfile.coolify @@ -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" diff --git a/apps/web/server/api/users/[id]/profile.get.ts b/apps/web/server/api/users/[id]/profile.get.ts index c7f26a0..c291f4b 100644 --- a/apps/web/server/api/users/[id]/profile.get.ts +++ b/apps/web/server/api/users/[id]/profile.get.ts @@ -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 } } })