feat: 개발 모드 → 배포 모드 전환
- 프론트엔드+백엔드 단일 컨테이너로 통합 (Dockerfile) - Fastify 정적 파일 서빙 + SPA fallback - @fastify/static 추가 - Caddy 프록시 대상 변경 (traeon-frontend → traeon) - 체크박스 w-5/w-0 CSS 충돌 수정 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
92b223eea1
commit
f2070aa8ba
8 changed files with 86 additions and 27 deletions
9
.dockerignore
Normal file
9
.dockerignore
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
node_modules
|
||||||
|
frontend/node_modules
|
||||||
|
backend/node_modules
|
||||||
|
frontend/dist
|
||||||
|
backend/dist
|
||||||
|
logo
|
||||||
|
docs
|
||||||
|
.git
|
||||||
|
*.md
|
||||||
20
Dockerfile
Normal file
20
Dockerfile
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
FROM node:20-alpine
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 프론트엔드 빌드
|
||||||
|
COPY frontend/package*.json ./frontend/
|
||||||
|
RUN cd frontend && npm install
|
||||||
|
COPY frontend/ ./frontend/
|
||||||
|
RUN cd frontend && npm run build
|
||||||
|
|
||||||
|
# 백엔드
|
||||||
|
COPY backend/package*.json ./backend/
|
||||||
|
RUN cd backend && npm install --omit=dev
|
||||||
|
COPY backend/ ./backend/
|
||||||
|
|
||||||
|
# 프론트엔드 빌드 결과를 백엔드 dist로 복사
|
||||||
|
RUN cp -r frontend/dist backend/dist
|
||||||
|
|
||||||
|
WORKDIR /app/backend
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["node", "src/server.js"]
|
||||||
|
|
@ -1,4 +1,21 @@
|
||||||
# 개발 모드
|
# 배포 모드
|
||||||
FROM node:20-alpine
|
FROM node:20-alpine AS base
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
CMD ["sh", "-c", "npm install && npm run dev"]
|
|
||||||
|
# 프론트엔드 빌드
|
||||||
|
COPY frontend/package*.json ./frontend/
|
||||||
|
RUN cd frontend && npm ci
|
||||||
|
COPY frontend/ ./frontend/
|
||||||
|
RUN cd frontend && npm run build
|
||||||
|
|
||||||
|
# 백엔드
|
||||||
|
COPY backend/package*.json ./backend/
|
||||||
|
RUN cd backend && npm ci --production
|
||||||
|
COPY backend/ ./backend/
|
||||||
|
|
||||||
|
# 프론트엔드 빌드 결과를 백엔드 dist로 복사
|
||||||
|
RUN cp -r frontend/dist backend/dist
|
||||||
|
|
||||||
|
WORKDIR /app/backend
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["node", "src/server.js"]
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fastify/cors": "^11.2.0",
|
"@fastify/cors": "^11.2.0",
|
||||||
|
"@fastify/static": "^8.0.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"fastify": "^5.2.1",
|
"fastify": "^5.2.1",
|
||||||
"fastify-plugin": "^5.0.1",
|
"fastify-plugin": "^5.0.1",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,17 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
import Fastify from 'fastify';
|
import Fastify from 'fastify';
|
||||||
import fastifyCors from '@fastify/cors';
|
import fastifyCors from '@fastify/cors';
|
||||||
|
import fastifyStatic from '@fastify/static';
|
||||||
import config from './config/index.js';
|
import config from './config/index.js';
|
||||||
import dbPlugin from './plugins/db.js';
|
import dbPlugin from './plugins/db.js';
|
||||||
import trackerPlugin from './plugins/tracker.js';
|
import trackerPlugin from './plugins/tracker.js';
|
||||||
import routes from './routes/index.js';
|
import routes from './routes/index.js';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
export async function buildApp(opts = {}) {
|
export async function buildApp(opts = {}) {
|
||||||
const fastify = Fastify({
|
const fastify = Fastify({
|
||||||
logger: {
|
logger: {
|
||||||
|
|
@ -33,5 +40,22 @@ export async function buildApp(opts = {}) {
|
||||||
return { status: 'ok', timestamp: new Date().toISOString() };
|
return { status: 'ok', timestamp: new Date().toISOString() };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 정적 파일 서빙 (프론트엔드 빌드 결과물)
|
||||||
|
const distPath = path.join(__dirname, '../dist');
|
||||||
|
if (fs.existsSync(distPath)) {
|
||||||
|
await fastify.register(fastifyStatic, {
|
||||||
|
root: distPath,
|
||||||
|
prefix: '/',
|
||||||
|
});
|
||||||
|
|
||||||
|
// SPA fallback
|
||||||
|
fastify.setNotFoundHandler((request, reply) => {
|
||||||
|
if (request.url.startsWith('/api/')) {
|
||||||
|
return reply.code(404).send({ error: 'Not found' });
|
||||||
|
}
|
||||||
|
return reply.sendFile('index.html');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return fastify;
|
return fastify;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,11 @@
|
||||||
services:
|
services:
|
||||||
traeon-frontend:
|
traeon:
|
||||||
build: ./frontend
|
build: .
|
||||||
container_name: traeon-frontend
|
container_name: traeon
|
||||||
labels:
|
|
||||||
- "com.centurylinklabs.watchtower.enable=false"
|
|
||||||
volumes:
|
|
||||||
- ./frontend:/app
|
|
||||||
depends_on:
|
|
||||||
- traeon-backend
|
|
||||||
networks:
|
|
||||||
- app
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
traeon-backend:
|
|
||||||
build: ./backend
|
|
||||||
container_name: traeon-backend
|
|
||||||
labels:
|
labels:
|
||||||
- "com.centurylinklabs.watchtower.enable=false"
|
- "com.centurylinklabs.watchtower.enable=false"
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
volumes:
|
|
||||||
- ./backend:/app
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- delivery-tracker
|
- delivery-tracker
|
||||||
networks:
|
networks:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
# 개발 모드
|
# 프론트엔드 빌드 전용
|
||||||
FROM node:20-alpine
|
FROM node:20-alpine AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
CMD ["sh", "-c", "npm install --include=dev && npm run dev -- --host 0.0.0.0"]
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
|
||||||
|
|
@ -262,10 +262,10 @@ function MainPage({ showForm, setShowForm }) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
toggleCheck(parcel.id);
|
toggleCheck(parcel.id);
|
||||||
}}
|
}}
|
||||||
className={`w-5 h-5 rounded-md border-2 flex items-center justify-center shrink-0 transition-all duration-300 ${
|
className={`h-5 rounded-md border-2 flex items-center justify-center shrink-0 transition-all duration-300 ${
|
||||||
deleteMode
|
deleteMode
|
||||||
? "opacity-100 scale-100 mr-0"
|
? "w-5 opacity-100 scale-100 mr-0"
|
||||||
: "opacity-0 scale-0 w-0 -mr-2"
|
: "w-0 opacity-0 scale-0 -mr-2"
|
||||||
} ${
|
} ${
|
||||||
deleteMode && checkedIds.has(parcel.id)
|
deleteMode && checkedIds.has(parcel.id)
|
||||||
? "bg-primary border-primary cursor-pointer"
|
? "bg-primary border-primary cursor-pointer"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue