260210:1700 Start Delpoy
Some checks failed
Spec Validation / validate-markdown (push) Has been cancelled
Spec Validation / validate-diagrams (push) Has been cancelled
Spec Validation / check-todos (push) Has been cancelled

This commit is contained in:
admin
2026-02-10 17:00:32 +07:00
parent d5e37d986f
commit d9df4e66b4
8 changed files with 642 additions and 11 deletions

63
.dockerignore Normal file
View File

@@ -0,0 +1,63 @@
# ============================================================
# Root .dockerignore — pnpm workspace monorepo
# Build context is workspace root for both backend and frontend
# ============================================================
# Dependencies (re-installed inside Docker)
node_modules
**/node_modules
# Git
.git
.github
.gitignore
# IDE / Editor
.vscode
.idea
.agent
.gemini
.specify
*.swp
# Build artifacts (rebuilt inside Docker)
backend/dist
frontend/.next
# Specs & docs (not needed in image)
specs
docs
diagrams
examples
# Test artifacts
coverage
**/*.spec.ts
**/*.test.ts
**/*.test.tsx
# Misc
*.log
*.md
!backend/README.md
!frontend/README.md
.prettierrc
.prettierignore
.spectral.yml
.cursorignore
.aignore
lcbp3.code-workspace
lcbp3_dev.session.sql
bfg.jar
fix_links.py
verify_links.py
link_audit_results*.txt
2git.ps1
scripts
# OS
.DS_Store
Thumbs.db
# Environment files
**/.env.local

47
backend/.dockerignore Normal file
View File

@@ -0,0 +1,47 @@
# Dependencies
node_modules
# Build output
dist
# Git
.git
.gitignore
# IDE / Editor
.vscode
.idea
*.swp
*.swo
# Test
test
coverage
**/*.spec.ts
**/*.test.ts
jest.config.*
docker-compose.test.yml
# Documentation
*.md
!README.md
docs
documentation
# Docker
Dockerfile
.dockerignore
docker-compose*.yml
# Environment
.env
.env.*
# OS
.DS_Store
Thumbs.db
# Misc
*.log
*.tgz
bfg.jar

82
backend/Dockerfile Normal file
View File

@@ -0,0 +1,82 @@
# ============================================================
# LCBP3 Backend — NestJS Production Dockerfile
# Multi-stage build: deps → build → production
# Target: QNAP TS-473A (Container Station)
# ============================================================
# Build context: workspace root (nap-dms.lcbp3/)
# Usage: docker build -f backend/Dockerfile -t lcbp3-backend:latest .
# ============================================================
# =========================
# Stage 1: Install Dependencies
# =========================
FROM node:22-alpine AS deps
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
# Copy workspace root manifests
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY backend/package.json ./backend/
# Install backend deps only using pnpm workspace filter
RUN pnpm install --frozen-lockfile --filter backend...
# =========================
# Stage 2: Build Application
# =========================
FROM node:22-alpine AS build
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
# Copy workspace structure
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/backend/node_modules ./backend/node_modules
# Copy backend source
COPY backend/ ./backend/
# Build NestJS → backend/dist
RUN cd backend && pnpm run build
# Prune dev dependencies
RUN pnpm prune --prod --filter backend...
# =========================
# Stage 3: Production Runtime
# =========================
FROM node:22-alpine AS production
# Install curl for healthcheck
RUN apk add --no-cache curl
WORKDIR /app
ENV TZ=Asia/Bangkok
ENV NODE_ENV=production
# Create non-root user
RUN addgroup -g 1001 -S nestjs && \
adduser -S nestjs -u 1001
# Copy production artifacts only
COPY --from=build --chown=nestjs:nestjs /app/backend/dist ./dist
COPY --from=build --chown=nestjs:nestjs /app/backend/node_modules ./node_modules
COPY --from=build --chown=nestjs:nestjs /app/backend/package.json ./
# Create uploads directory (Two-Phase Storage)
RUN mkdir -p /app/uploads/temp /app/uploads/permanent && \
chown -R nestjs:nestjs /app/uploads
USER nestjs
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=30s \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "dist/main"]

46
frontend/.dockerignore Normal file
View File

@@ -0,0 +1,46 @@
# Dependencies
node_modules
.ignored_node_modules
# Build output
.next
# Git
.git
.gitignore
# IDE / Editor
.vscode
.idea
*.swp
*.swo
# Test
**/*.test.ts
**/*.test.tsx
**/*.spec.ts
vitest.config.ts
vitest.setup.ts
coverage
# Documentation
*.md
!README.md
# Docker
Dockerfile
.dockerignore
# Environment (local dev only)
.env.local
# OS
.DS_Store
Thumbs.db
# Build logs
*.log
build-output.txt
build-detailed.txt
tsc.log
tsconfig.tsbuildinfo

77
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,77 @@
# ============================================================
# LCBP3 Frontend — Next.js Production Dockerfile
# Multi-stage build: deps → build → production (standalone)
# Target: QNAP TS-473A (Container Station)
# ============================================================
# Build context: workspace root (nap-dms.lcbp3/)
# Usage: docker build -f frontend/Dockerfile -t lcbp3-frontend:latest .
# ============================================================
# =========================
# Stage 1: Install Dependencies
# =========================
FROM node:22-alpine AS deps
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
# Copy workspace root manifests
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY frontend/package.json ./frontend/
# Install frontend deps only
RUN pnpm install --frozen-lockfile --filter lcbp3-frontend...
# =========================
# Stage 2: Build Application
# =========================
FROM node:22-alpine AS build
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
# Copy workspace structure
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/frontend/node_modules ./frontend/node_modules
# Copy frontend source
COPY frontend/ ./frontend/
# NEXT_PUBLIC_* vars must be set at BUILD TIME (baked into client bundle)
ARG NEXT_PUBLIC_API_URL=https://backend.np-dms.work/api
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
# Build Next.js → frontend/.next/standalone
RUN cd frontend && pnpm run build
# =========================
# Stage 3: Production Runtime
# =========================
FROM node:22-alpine AS production
WORKDIR /app
ENV TZ=Asia/Bangkok
ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
# Create non-root user
RUN addgroup -g 1001 -S nextjs && \
adduser -S nextjs -u 1001
# Copy standalone output from build
COPY --from=build --chown=nextjs:nextjs /app/frontend/.next/standalone ./
COPY --from=build --chown=nextjs:nextjs /app/frontend/.next/static ./.next/static
USER nextjs
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=20s \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1
CMD ["node", "server.js"]

View File

@@ -0,0 +1,193 @@
# การ Deploy Application (Backend + Frontend) บน QNAP
> 📍 **Version:** v1.7.0
> 🖥️ **Server:** QNAP TS-473A (Container Station)
> 🔗 **Docker Compose Path:** `/share/np-dms/app/docker-compose.yml`
---
## 📋 Prerequisites
ก่อน deploy ต้องมี services เหล่านี้รันอยู่แล้ว:
| Service | Container Name | Docker Compose | Status |
| :------------- | :------------- | :--------------------------------- | :----- |
| MariaDB | `mariadb` | `lcbp3-db` (MariaDB_setting.md) | ✅ |
| Redis | `cache` | `services` (04_Service_setting.md) | ✅ |
| Elasticsearch | `search` | `services` (04_Service_setting.md) | ✅ |
| NPM | `npm` | `lcbp3-npm` (NPM_setting.md) | ✅ |
| Docker Network | `lcbp3` | `docker network create lcbp3` | ✅ |
---
## 1. Build Docker Images
### Option A: Build บน Dev Machine แล้ว Transfer
```bash
# อยู่ที่ workspace root (nap-dms.lcbp3/)
# Build Backend
docker build -f backend/Dockerfile -t lcbp3-backend:latest .
# Build Frontend (NEXT_PUBLIC_API_URL bake เข้าไปตอน build)
docker build -f frontend/Dockerfile \
--build-arg NEXT_PUBLIC_API_URL=https://backend.np-dms.work/api \
-t lcbp3-frontend:latest .
# Export เป็น .tar เพื่อ Transfer
docker save lcbp3-backend:latest | gzip > lcbp3-backend.tar.gz
docker save lcbp3-frontend:latest | gzip > lcbp3-frontend.tar.gz
# Transfer ไปยัง QNAP (ผ่าน SCP หรือ Shared Folder)
scp lcbp3-*.tar.gz admin@192.168.10.8:/share/np-dms/app/
```
### Option B: Build บน QNAP โดยตรง (SSH)
```bash
# SSH เข้า QNAP
ssh admin@192.168.10.8
# Clone หรือ Pull code จาก Gitea
cd /share/np-dms/app/source
git pull origin main
# Build images
docker build -f backend/Dockerfile -t lcbp3-backend:latest .
docker build -f frontend/Dockerfile \
--build-arg NEXT_PUBLIC_API_URL=https://backend.np-dms.work/api \
-t lcbp3-frontend:latest .
```
---
## 2. Load Images บน QNAP (เฉพาะ Option A)
```bash
# SSH เข้า QNAP
ssh admin@192.168.10.8
# Load images
docker load < /share/np-dms/app/lcbp3-backend.tar.gz
docker load < /share/np-dms/app/lcbp3-frontend.tar.gz
# ตรวจสอบ
docker images | grep lcbp3
```
---
## 3. สร้าง Directories และกำหนดสิทธิ์
```bash
# สร้าง directories สำหรับ volumes
mkdir -p /share/dms-data/uploads/temp
mkdir -p /share/dms-data/uploads/permanent
mkdir -p /share/dms-data/logs/backend
mkdir -p /share/np-dms/app
# กำหนดสิทธิ์ให้ non-root user ใน container (UID 1001)
chown -R 1001:1001 /share/dms-data/uploads
chown -R 1001:1001 /share/dms-data/logs/backend
chmod -R 750 /share/dms-data/uploads
```
---
## 4. Deploy ผ่าน Container Station
### 4.1 Copy docker-compose.yml
คัดลอกไฟล์ `specs/08-infrastructure/docker-compose-app.yml` ไปยัง QNAP:
```bash
# วางไฟล์ที่ path
/share/np-dms/app/docker-compose.yml
```
### 4.2 สร้าง Application ใน Container Station
1. เปิด **Container Station** บน QNAP Web UI
2. ไปที่ **Applications****Create**
3. เลือก **Create Application**
4. ตั้งชื่อ Application: `lcbp3-app`
5. วาง (Paste) เนื้อหาจาก `docker-compose-app.yml`
6. แก้ไข Environment Variables ตามต้องการ (โดยเฉพาะ Secrets)
7. กด **Create** เพื่อ deploy
> ⚠️ **สำคัญ:** ตรวจสอบ environment variables ก่อน deploy:
> - `DB_PASSWORD` — Password ของ MariaDB
> - `REDIS_PASSWORD` — Password ของ Redis
> - `JWT_SECRET` — Secret key สำหรับ JWT Tokens
> - `AUTH_SECRET` — Secret key สำหรับ NextAuth
### 4.3 ตรวจสอบ Container Status
ใน Container Station → Applications → `lcbp3-app`:
-`backend` — Status: **Running** (healthy)
-`frontend` — Status: **Running** (healthy)
---
## 5. Verify Deployment
### ตรวจสอบ Health
```bash
# Backend health (จากภายใน Docker network)
docker exec frontend wget -qO- http://backend:3000/health
# Frontend (ผ่าน NPM)
curl -I https://lcbp3.np-dms.work
# Backend API (ผ่าน NPM)
curl -I https://backend.np-dms.work/api
```
### ตรวจสอบ Logs
```bash
# ดู logs ใน Container Station UI
# หรือผ่าน CLI:
docker logs -f backend
docker logs -f frontend
```
---
## 6. Update / Re-deploy
เมื่อต้องการ deploy version ใหม่:
```bash
# 1. Build images ใหม่ (บน Dev Machine)
docker build -f backend/Dockerfile -t lcbp3-backend:latest .
docker build -f frontend/Dockerfile -t lcbp3-frontend:latest .
# 2. Export & Transfer
docker save lcbp3-backend:latest | gzip > lcbp3-backend.tar.gz
docker save lcbp3-frontend:latest | gzip > lcbp3-frontend.tar.gz
scp lcbp3-*.tar.gz admin@192.168.10.8:/share/np-dms/app/
# 3. Load บน QNAP
ssh admin@192.168.10.8
docker load < /share/np-dms/app/lcbp3-backend.tar.gz
docker load < /share/np-dms/app/lcbp3-frontend.tar.gz
# 4. Restart ใน Container Station
# Applications → lcbp3-app → Restart
```
---
## 📦 Resource Summary
| Service | Image | CPU Limit | Memory Limit | Port |
| :----------- | :---------------------- | :-------- | :----------- | :--- |
| **backend** | `lcbp3-backend:latest` | 2.0 | 1.5 GB | 3000 |
| **frontend** | `lcbp3-frontend:latest` | 2.0 | 2 GB | 3000 |
> 📖 NPM Proxy Hosts ตั้งค่าเรียบร้อยแล้ว:
> - `lcbp3.np-dms.work` → `frontend:3000`
> - `backend.np-dms.work` → `backend:3000`

View File

@@ -182,12 +182,13 @@ graph TB
### Core Services (QNAP) ### Core Services (QNAP)
| ไฟล์ | Application | Services | Path บน QNAP | | ไฟล์ | Application | Services | Path บน QNAP |
| :--------------------------------------- | :---------- | :---------------------------------------- | :------------------------ | | :----------------------------------------------- | :---------- | :---------------------------------------- | :------------------------ |
| [MariaDB_setting.md](MariaDB_setting.md) | `lcbp3-db` | `mariadb`, `pma` | `/share/np-dms/mariadb/` | | [MariaDB_setting.md](MariaDB_setting.md) | `lcbp3-db` | `mariadb`, `pma` | `/share/np-dms/mariadb/` |
| [NPM_setting.md](NPM_setting.md) | `lcbp3-npm` | `npm`, `landing` | `/share/np-dms/npm/` | | [NPM_setting.md](NPM_setting.md) | `lcbp3-npm` | `npm`, `landing` | `/share/np-dms/npm/` |
| [Service_setting.md](Service_setting.md) | `services` | `cache` (Redis), `search` (Elasticsearch) | `/share/np-dms/services/` | | [Service_setting.md](Service_setting.md) | `services` | `cache` (Redis), `search` (Elasticsearch) | `/share/np-dms/services/` |
| [Gitea_setting.md](Gitea_setting.md) | `git` | `gitea` | `/share/np-dms/gitea/` | | [Gitea_setting.md](Gitea_setting.md) | `git` | `gitea` | `/share/np-dms/gitea/` |
| [n8n_setting.md](n8n_setting.md) | `n8n` | `n8n` | `/share/np-dms/n8n/` | | [n8n_setting.md](n8n_setting.md) | `n8n` | `n8n` | `/share/np-dms/n8n/` |
| [docker-compose-app.yml](docker-compose-app.yml) | `lcbp3-app` | `backend` (NestJS), `frontend` (Next.js) | `/share/np-dms/app/` |
### Infrastructure Services (ASUSTOR) ### Infrastructure Services (ASUSTOR)
@@ -334,9 +335,10 @@ docker exec mariadb mysqldump -u root -p lcbp3 > backup.sql
## 📚 เอกสารเสริม ## 📚 เอกสารเสริม
| ไฟล์ | คำอธิบาย | | ไฟล์ | คำอธิบาย |
| :------------------------------- | :------------------------------------------------ | | :------------------------------------------- | :-------------------------------------------------------- |
| [Git_command.md](Git_command.md) | คำสั่ง Git + Gitea Cheat Sheet | | [Git_command.md](Git_command.md) | คำสั่ง Git + Gitea Cheat Sheet |
| [lcbp3-db.md](lcbp3-db.md) | Docker Compose สำหรับ MariaDB (alternative version) | | [lcbp3-db.md](lcbp3-db.md) | Docker Compose สำหรับ MariaDB (alternative version) |
| [09_app_deployment.md](09_app_deployment.md) | ขั้นตอน Deploy Backend + Frontend บน QNAP Container Station |
--- ---

View File

@@ -0,0 +1,121 @@
# File: /share/np-dms/app/docker-compose.yml
# DMS Container v1.7.0: Application Stack (Backend + Frontend)
# Application name: lcbp3-app
# ============================================================
# ⚠️ ใช้งานร่วมกับ services อื่นที่รันอยู่แล้วบน QNAP:
# - mariadb (lcbp3-db)
# - cache (services)
# - search (services)
# - npm (lcbp3-npm)
# ============================================================
x-restart: &restart_policy
restart: unless-stopped
x-logging: &default_logging
logging:
driver: 'json-file'
options:
max-size: '10m'
max-file: '5'
networks:
lcbp3:
external: true
services:
# ----------------------------------------------------------------
# 1. Backend API (NestJS)
# Service Name: backend (ตามที่ NPM อ้างอิง → backend:3000)
# ----------------------------------------------------------------
backend:
<<: [*restart_policy, *default_logging]
image: lcbp3-backend:latest
container_name: backend
stdin_open: true
tty: true
deploy:
resources:
limits:
cpus: '2.0'
memory: 1536M
reservations:
cpus: '0.5'
memory: 512M
environment:
TZ: 'Asia/Bangkok'
NODE_ENV: 'production'
# --- Database ---
DB_HOST: 'mariadb'
DB_PORT: '3306'
DB_NAME: 'lcbp3'
DB_USER: 'center'
DB_PASSWORD: 'Center#2025'
# --- Redis ---
REDIS_HOST: 'cache'
REDIS_PORT: '6379'
REDIS_PASSWORD: 'Center2025'
# --- Elasticsearch ---
ELASTICSEARCH_HOST: 'search'
ELASTICSEARCH_PORT: '9200'
# --- JWT ---
JWT_SECRET: 'eebc122aa65adde8c76c6a0847d9649b2b67a06db1504693e6c912e51499b76e'
JWT_EXPIRES_IN: '8h'
# --- Numbering ---
NUMBERING_LOCK_TIMEOUT: '5000'
NUMBERING_RESERVATION_TTL: '300'
# --- File Upload ---
UPLOAD_TEMP_DIR: '/app/uploads/temp'
UPLOAD_PERMANENT_DIR: '/app/uploads/permanent'
MAX_FILE_SIZE: '52428800'
networks:
- lcbp3
volumes:
# Two-Phase Storage: จัดเก็บไฟล์นอก container
- '/share/dms-data/uploads/temp:/app/uploads/temp'
- '/share/dms-data/uploads/permanent:/app/uploads/permanent'
- '/share/dms-data/logs/backend:/app/logs'
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# ----------------------------------------------------------------
# 2. Frontend Web App (Next.js)
# Service Name: frontend (ตามที่ NPM อ้างอิง → frontend:3000)
# ----------------------------------------------------------------
frontend:
<<: [*restart_policy, *default_logging]
image: lcbp3-frontend:latest
container_name: frontend
stdin_open: true
tty: true
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
cpus: '0.25'
memory: 512M
environment:
TZ: 'Asia/Bangkok'
NODE_ENV: 'production'
HOSTNAME: '0.0.0.0'
PORT: '3000'
# --- NextAuth ---
AUTH_SECRET: 'eebc122aa65adde8c76c6a0847d9649b2b67a06db1504693e6c912e51499b76e'
AUTH_URL: 'https://lcbp3.np-dms.work'
networks:
- lcbp3
healthcheck:
test: ['CMD-SHELL', 'wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1']
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
depends_on:
backend:
condition: service_healthy