Deploy skeleton-app
Build and Deploy / build-and-push (push) Successful in 59s Details

This commit is contained in:
ImNotTheGuy 2026-04-21 14:57:53 +02:00
parent 083982814f
commit 6b31b6e68f
6 changed files with 55 additions and 32 deletions

View File

@ -18,7 +18,7 @@ jobs:
username: ${{ gitea.actor }}
password: ${{ secrets.CI_TOKEN }}
- name: Build and Pushz
- name: Build and Push
uses: docker/build-push-action@v4
with:
context: .
@ -28,5 +28,6 @@ jobs:
- name: Deploy to Server
run: |
# Here we tell the server to pull the new image and restart
echo "${{ secrets.CI_TOKEN }}" | docker login git.ludops.com -u ${{ gitea.actor }} --password-stdin
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d

1
.npmrc Normal file
View File

@ -0,0 +1 @@
inject-workspace-packages=true

View File

@ -1,36 +1,37 @@
# --- STAGE 1: Base & Dependencies ---
FROM node:20-alpine AS base
# --- STAGE 1: Base ---
FROM node:24-alpine AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable
WORKDIR /app
# Copy lockfiles and workspace configs
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json turbo.json ./
# Copy all package.jsons to allow pnpm to link workspaces
COPY apps/api/package.json ./apps/api/
COPY apps/web/package.json ./apps/web/
COPY packages/shared/package.json ./packages/shared/
RUN pnpm install --frozen-lockfile
# --- STAGE 2: Build ---
# --- STAGE 2: Build everything ---
FROM base AS build
COPY . .
# This runs 'turbo run build' which should create 'dist' in both apps
RUN pnpm install --frozen-lockfile
RUN pnpm turbo run build
# --- STAGE 3: Runner (The tiny production image) ---
FROM node:20-alpine AS runner
# --- STAGE 3: Extract for Production ---
# This "flattens" the api and its node_modules into a standalone folder
RUN pnpm deploy --filter=api --prod /prod/api
# --- STAGE 4: Runner ---
FROM node:24-alpine AS runner
WORKDIR /app
# IMPORTANT: We copy from 'build' stage, not 'base'
# We check if the folders exist before copying to avoid the error you saw
COPY --from=build /app/apps/api/dist ./api
# Copy the standalone API (includes its own local node_modules)
COPY --from=build /prod/api .
# Copy the web dist into the location the API expects
# Based on your code, it looks for ../web-dist or ./web-dist
COPY --from=build /app/apps/web/dist ./web-dist
COPY --from=build /app/node_modules ./node_modules
# We need the shared package if the API imports it directly as source
# But pnpm deploy usually handles the shared package if it's built
COPY --from=build /app/packages/shared ./packages/shared
EXPOSE 3000
# Update this path to wherever your compiled Fastify entry point is
CMD ["node", "api/src/index.ts"]
ENV NODE_ENV=production
# Since we are now inside the "api" folder essentially:
CMD ["node", "dist/index.js"]

View File

@ -11,26 +11,26 @@ const fastify = Fastify({ logger: true });
// API Route
fastify.get('/api/status', async (): Promise<AppStatus> => {
return { status: 'OK', version: '1.0.0', database: true };
return { status: 'OK', version: '1.0.0', database: true };
});
// Serve Frontend (Vite Dist)
const webDistPath = process.env.NODE_ENV === 'production'
? path.join(__dirname, '../web-dist')
: path.join(__dirname, '../../web/dist');
? path.join(__dirname, 'web-dist') // Adjusted for the flattened Docker structure
: path.join(__dirname, '../../web/dist');
fastify.register(fastifyStatic, {
root: webDistPath,
prefix: '/',
root: webDistPath,
prefix: '/',
});
// SPA Routing: Redirect everything else to index.html
fastify.setNotFoundHandler((req, reply) => {
if (req.url.startsWith('/api')) {
reply.code(404).send({ error: 'Not Found' });
} else {
reply.sendFile('index.html');
}
if (req.url.startsWith('/api')) {
reply.code(404).send({ error: 'Not Found' });
} else {
reply.sendFile('index.html');
}
});
fastify.listen({ port: 3000, host: '0.0.0.0' });

19
docker-compose.prod.yml Normal file
View File

@ -0,0 +1,19 @@
services:
skeleton-app:
image: git.ludops.com/ludops/ludops-skeleton:latest
container_name: ludops-skeleton-app
restart: always
environment:
- NODE_ENV=production
- PORT=3000
# We point to the shared DB we set up earlier
- DATABASE_URL=postgres://gitea:gitea@ludops-postgres:5432/skeleton_db
networks:
- proxy-tier # For NPM to find us
- infrastructure_infra-network # For us to find the Postgres DB
networks:
proxy-tier:
external: true
infrastructure_infra-network:
external: true

View File

@ -3,6 +3,7 @@ lockfileVersion: '9.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
injectWorkspacePackages: true
importers: