Add Dockerfile and fix pnpm setup for Dokploy

This commit is contained in:
Mackie 2026-05-22 01:45:11 +08:00
parent 23477e7a2d
commit 35d75607b0
6 changed files with 10995 additions and 114 deletions

View file

@ -1,71 +1,25 @@
# To use this Dockerfile, you have to set `output: 'standalone'` in your next.config.js file.
# From https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile
FROM node:22.17.0-alpine AS base
# Install dependencies only when needed # Install dependencies only when needed
FROM base AS deps FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat RUN apk add --no-cache libc6-compat
WORKDIR /app WORKDIR /app
# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./ COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \ RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \ elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ elif [ -f pnpm-lock.yaml ]; then corepack enable && corepack prepare pnpm@10.11.0 --activate && pnpm i --frozen-lockfile; \
else echo "Lockfile not found." && exit 1; \ else echo "Lockfile not found." && exit 1; \
fi fi
# Rebuild the source code only when needed # Rebuild the source code only when needed
FROM base AS builder FROM base AS builder
WORKDIR /app WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN \ RUN \
if [ -f yarn.lock ]; then yarn run build; \ if [ -f yarn.lock ]; then yarn run build; \
elif [ -f package-lock.json ]; then npm run build; \ elif [ -f package-lock.json ]; then npm run build; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \ elif [ -f pnpm-lock.yaml ]; then corepack enable && corepack prepare pnpm@10.11.0 --activate && pnpm run build; \
else echo "Lockfile not found." && exit 1; \ else echo "Lockfile not found." && exit 1; \
fi fi
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
# ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Remove this line if you do not have this folder
COPY --from=builder /app/public ./public
# Set the correct permission for prerender cache
RUN mkdir .next
RUN chown nextjs:nodejs .next
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
# server.js is created by next build from the standalone output
# https://nextjs.org/docs/pages/api-reference/next-config-js/output
CMD HOSTNAME="0.0.0.0" node server.js

0
payload_dump.sql Normal file
View file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

9
src/migrations/index.ts Normal file
View file

@ -0,0 +1,9 @@
import * as migration_20260521_173007 from './20260521_173007';
export const migrations = [
{
up: migration_20260521_173007.up,
down: migration_20260521_173007.down,
name: '20260521_173007'
},
];

View file

@ -106,7 +106,7 @@ export interface Config {
'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>; 'payload-migrations': PayloadMigrationsSelect<false> | PayloadMigrationsSelect<true>;
}; };
db: { db: {
defaultIDType: string; defaultIDType: number;
}; };
fallbackLocale: null; fallbackLocale: null;
globals: { globals: {
@ -156,7 +156,7 @@ export interface UserAuthOperations {
* via the `definition` "pages". * via the `definition` "pages".
*/ */
export interface Page { export interface Page {
id: string; id: number;
title: string; title: string;
hero: { hero: {
type: 'none' | 'highImpact' | 'mediumImpact' | 'lowImpact'; type: 'none' | 'highImpact' | 'mediumImpact' | 'lowImpact';
@ -183,11 +183,11 @@ export interface Page {
reference?: reference?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null); } | null);
url?: string | null; url?: string | null;
label: string; label: string;
@ -199,7 +199,7 @@ export interface Page {
id?: string | null; id?: string | null;
}[] }[]
| null; | null;
media?: (string | null) | Media; media?: (number | null) | Media;
}; };
layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock | FormBlock)[]; layout: (CallToActionBlock | ContentBlock | MediaBlock | ArchiveBlock | FormBlock)[];
meta?: { meta?: {
@ -207,7 +207,7 @@ export interface Page {
/** /**
* Maximum upload file size: 12MB. Recommended file size for images is <500KB. * Maximum upload file size: 12MB. Recommended file size for images is <500KB.
*/ */
image?: (string | null) | Media; image?: (number | null) | Media;
description?: string | null; description?: string | null;
}; };
publishedAt?: string | null; publishedAt?: string | null;
@ -225,9 +225,9 @@ export interface Page {
* via the `definition` "posts". * via the `definition` "posts".
*/ */
export interface Post { export interface Post {
id: string; id: number;
title: string; title: string;
heroImage?: (string | null) | Media; heroImage?: (number | null) | Media;
content: { content: {
root: { root: {
type: string; type: string;
@ -243,18 +243,18 @@ export interface Post {
}; };
[k: string]: unknown; [k: string]: unknown;
}; };
relatedPosts?: (string | Post)[] | null; relatedPosts?: (number | Post)[] | null;
categories?: (string | Category)[] | null; categories?: (number | Category)[] | null;
meta?: { meta?: {
title?: string | null; title?: string | null;
/** /**
* Maximum upload file size: 12MB. Recommended file size for images is <500KB. * Maximum upload file size: 12MB. Recommended file size for images is <500KB.
*/ */
image?: (string | null) | Media; image?: (number | null) | Media;
description?: string | null; description?: string | null;
}; };
publishedAt?: string | null; publishedAt?: string | null;
authors?: (string | User)[] | null; authors?: (number | User)[] | null;
populatedAuthors?: populatedAuthors?:
| { | {
id?: string | null; id?: string | null;
@ -275,7 +275,7 @@ export interface Post {
* via the `definition` "media". * via the `definition` "media".
*/ */
export interface Media { export interface Media {
id: string; id: number;
alt?: string | null; alt?: string | null;
caption?: { caption?: {
root: { root: {
@ -292,7 +292,7 @@ export interface Media {
}; };
[k: string]: unknown; [k: string]: unknown;
} | null; } | null;
folder?: (string | null) | FolderInterface; folder?: (number | null) | FolderInterface;
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
url?: string | null; url?: string | null;
@ -368,18 +368,18 @@ export interface Media {
* via the `definition` "payload-folders". * via the `definition` "payload-folders".
*/ */
export interface FolderInterface { export interface FolderInterface {
id: string; id: number;
name: string; name: string;
folder?: (string | null) | FolderInterface; folder?: (number | null) | FolderInterface;
documentsAndFolders?: { documentsAndFolders?: {
docs?: ( docs?: (
| { | {
relationTo?: 'payload-folders'; relationTo?: 'payload-folders';
value: string | FolderInterface; value: number | FolderInterface;
} }
| { | {
relationTo?: 'media'; relationTo?: 'media';
value: string | Media; value: number | Media;
} }
)[]; )[];
hasNextPage?: boolean; hasNextPage?: boolean;
@ -394,17 +394,17 @@ export interface FolderInterface {
* via the `definition` "categories". * via the `definition` "categories".
*/ */
export interface Category { export interface Category {
id: string; id: number;
title: string; title: string;
/** /**
* When enabled, the slug will auto-generate from the title field on save and autosave. * When enabled, the slug will auto-generate from the title field on save and autosave.
*/ */
generateSlug?: boolean | null; generateSlug?: boolean | null;
slug: string; slug: string;
parent?: (string | null) | Category; parent?: (number | null) | Category;
breadcrumbs?: breadcrumbs?:
| { | {
doc?: (string | null) | Category; doc?: (number | null) | Category;
url?: string | null; url?: string | null;
label?: string | null; label?: string | null;
id?: string | null; id?: string | null;
@ -418,7 +418,7 @@ export interface Category {
* via the `definition` "users". * via the `definition` "users".
*/ */
export interface User { export interface User {
id: string; id: number;
name?: string | null; name?: string | null;
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
@ -467,11 +467,11 @@ export interface CallToActionBlock {
reference?: reference?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null); } | null);
url?: string | null; url?: string | null;
label: string; label: string;
@ -517,11 +517,11 @@ export interface ContentBlock {
reference?: reference?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null); } | null);
url?: string | null; url?: string | null;
label: string; label: string;
@ -542,7 +542,7 @@ export interface ContentBlock {
* via the `definition` "MediaBlock". * via the `definition` "MediaBlock".
*/ */
export interface MediaBlock { export interface MediaBlock {
media: string | Media; media: number | Media;
id?: string | null; id?: string | null;
blockName?: string | null; blockName?: string | null;
blockType: 'mediaBlock'; blockType: 'mediaBlock';
@ -569,12 +569,12 @@ export interface ArchiveBlock {
} | null; } | null;
populateBy?: ('collection' | 'selection') | null; populateBy?: ('collection' | 'selection') | null;
relationTo?: 'posts' | null; relationTo?: 'posts' | null;
categories?: (string | Category)[] | null; categories?: (number | Category)[] | null;
limit?: number | null; limit?: number | null;
selectedDocs?: selectedDocs?:
| { | {
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
}[] }[]
| null; | null;
id?: string | null; id?: string | null;
@ -586,7 +586,7 @@ export interface ArchiveBlock {
* via the `definition` "FormBlock". * via the `definition` "FormBlock".
*/ */
export interface FormBlock { export interface FormBlock {
form: string | Form; form: number | Form;
enableIntro?: boolean | null; enableIntro?: boolean | null;
introContent?: { introContent?: {
root: { root: {
@ -612,7 +612,7 @@ export interface FormBlock {
* via the `definition` "forms". * via the `definition` "forms".
*/ */
export interface Form { export interface Form {
id: string; id: number;
title: string; title: string;
fields?: fields?:
| ( | (
@ -786,7 +786,7 @@ export interface Form {
* via the `definition` "redirects". * via the `definition` "redirects".
*/ */
export interface Redirect { export interface Redirect {
id: string; id: number;
/** /**
* You will need to rebuild the website when changing this field. * You will need to rebuild the website when changing this field.
*/ */
@ -796,11 +796,11 @@ export interface Redirect {
reference?: reference?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null); } | null);
url?: string | null; url?: string | null;
}; };
@ -812,8 +812,8 @@ export interface Redirect {
* via the `definition` "form-submissions". * via the `definition` "form-submissions".
*/ */
export interface FormSubmission { export interface FormSubmission {
id: string; id: number;
form: string | Form; form: number | Form;
submissionData?: submissionData?:
| { | {
field: string; field: string;
@ -831,18 +831,18 @@ export interface FormSubmission {
* via the `definition` "search". * via the `definition` "search".
*/ */
export interface Search { export interface Search {
id: string; id: number;
title?: string | null; title?: string | null;
priority?: number | null; priority?: number | null;
doc: { doc: {
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
}; };
slug?: string | null; slug?: string | null;
meta?: { meta?: {
title?: string | null; title?: string | null;
description?: string | null; description?: string | null;
image?: (string | null) | Media; image?: (number | null) | Media;
}; };
categories?: categories?:
| { | {
@ -860,7 +860,7 @@ export interface Search {
* via the `definition` "payload-kv". * via the `definition` "payload-kv".
*/ */
export interface PayloadKv { export interface PayloadKv {
id: string; id: number;
key: string; key: string;
data: data:
| { | {
@ -877,7 +877,7 @@ export interface PayloadKv {
* via the `definition` "payload-jobs". * via the `definition` "payload-jobs".
*/ */
export interface PayloadJob { export interface PayloadJob {
id: string; id: number;
/** /**
* Input data provided to the job * Input data provided to the job
*/ */
@ -969,52 +969,52 @@ export interface PayloadJob {
* via the `definition` "payload-locked-documents". * via the `definition` "payload-locked-documents".
*/ */
export interface PayloadLockedDocument { export interface PayloadLockedDocument {
id: string; id: number;
document?: document?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null) } | null)
| ({ | ({
relationTo: 'media'; relationTo: 'media';
value: string | Media; value: number | Media;
} | null) } | null)
| ({ | ({
relationTo: 'categories'; relationTo: 'categories';
value: string | Category; value: number | Category;
} | null) } | null)
| ({ | ({
relationTo: 'users'; relationTo: 'users';
value: string | User; value: number | User;
} | null) } | null)
| ({ | ({
relationTo: 'redirects'; relationTo: 'redirects';
value: string | Redirect; value: number | Redirect;
} | null) } | null)
| ({ | ({
relationTo: 'forms'; relationTo: 'forms';
value: string | Form; value: number | Form;
} | null) } | null)
| ({ | ({
relationTo: 'form-submissions'; relationTo: 'form-submissions';
value: string | FormSubmission; value: number | FormSubmission;
} | null) } | null)
| ({ | ({
relationTo: 'search'; relationTo: 'search';
value: string | Search; value: number | Search;
} | null) } | null)
| ({ | ({
relationTo: 'payload-folders'; relationTo: 'payload-folders';
value: string | FolderInterface; value: number | FolderInterface;
} | null); } | null);
globalSlug?: string | null; globalSlug?: string | null;
user: { user: {
relationTo: 'users'; relationTo: 'users';
value: string | User; value: number | User;
}; };
updatedAt: string; updatedAt: string;
createdAt: string; createdAt: string;
@ -1024,10 +1024,10 @@ export interface PayloadLockedDocument {
* via the `definition` "payload-preferences". * via the `definition` "payload-preferences".
*/ */
export interface PayloadPreference { export interface PayloadPreference {
id: string; id: number;
user: { user: {
relationTo: 'users'; relationTo: 'users';
value: string | User; value: number | User;
}; };
key?: string | null; key?: string | null;
value?: value?:
@ -1047,7 +1047,7 @@ export interface PayloadPreference {
* via the `definition` "payload-migrations". * via the `definition` "payload-migrations".
*/ */
export interface PayloadMigration { export interface PayloadMigration {
id: string; id: number;
name?: string | null; name?: string | null;
batch?: number | null; batch?: number | null;
updatedAt: string; updatedAt: string;
@ -1636,7 +1636,7 @@ export interface PayloadMigrationsSelect<T extends boolean = true> {
* via the `definition` "header". * via the `definition` "header".
*/ */
export interface Header { export interface Header {
id: string; id: number;
navItems?: navItems?:
| { | {
link: { link: {
@ -1645,11 +1645,11 @@ export interface Header {
reference?: reference?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null); } | null);
url?: string | null; url?: string | null;
label: string; label: string;
@ -1665,7 +1665,7 @@ export interface Header {
* via the `definition` "footer". * via the `definition` "footer".
*/ */
export interface Footer { export interface Footer {
id: string; id: number;
navItems?: navItems?:
| { | {
link: { link: {
@ -1674,11 +1674,11 @@ export interface Footer {
reference?: reference?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null); } | null);
url?: string | null; url?: string | null;
label: string; label: string;
@ -1756,14 +1756,14 @@ export interface TaskSchedulePublish {
doc?: doc?:
| ({ | ({
relationTo: 'pages'; relationTo: 'pages';
value: string | Page; value: number | Page;
} | null) } | null)
| ({ | ({
relationTo: 'posts'; relationTo: 'posts';
value: string | Post; value: number | Post;
} | null); } | null);
global?: string | null; global?: string | null;
user?: (string | null) | User; user?: (number | null) | User;
}; };
output?: unknown; output?: unknown;
} }