mirror of
https://git.victorphan.net/basketballcantho/ten-project.git
synced 2026-08-05 13:33:10 +07:00
hoàn thành docker compose giai đoạn 1
This commit is contained in:
@@ -17,3 +17,8 @@ ACCESS_TOKEN_EXPIRE_MINUTES=60
|
|||||||
# ── Ports ─────────────────────────────────────────────────────────────────────
|
# ── Ports ─────────────────────────────────────────────────────────────────────
|
||||||
# Port exposed on the host for the Next.js frontend
|
# Port exposed on the host for the Next.js frontend
|
||||||
FRONTEND_PORT=3000
|
FRONTEND_PORT=3000
|
||||||
|
|
||||||
|
# ── Docker Hub images (optional — leave blank to build locally) ───────────────
|
||||||
|
# Set these on the target machine so docker compose pull works without building
|
||||||
|
# BACKEND_IMAGE=your_dockerhub_username/lms-backend:latest
|
||||||
|
# FRONTEND_IMAGE=your_dockerhub_username/lms-frontend:latest
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
import os
|
||||||
|
|
||||||
from ..database import get_db
|
from ..database import get_db
|
||||||
from ..dependencies import get_current_user
|
from ..dependencies import get_current_user
|
||||||
@@ -16,6 +17,7 @@ router = APIRouter(prefix="/auth", tags=["auth"])
|
|||||||
|
|
||||||
_COOKIE_NAME = "access_token"
|
_COOKIE_NAME = "access_token"
|
||||||
_COOKIE_MAX_AGE = ACCESS_TOKEN_EXPIRE_MINUTES * 60 # seconds
|
_COOKIE_MAX_AGE = ACCESS_TOKEN_EXPIRE_MINUTES * 60 # seconds
|
||||||
|
_COOKIE_SECURE = os.getenv("COOKIE_SECURE", "false").lower() == "true"
|
||||||
|
|
||||||
|
|
||||||
def _set_auth_cookie(response: Response, user_id: int) -> None:
|
def _set_auth_cookie(response: Response, user_id: int) -> None:
|
||||||
@@ -24,7 +26,7 @@ def _set_auth_cookie(response: Response, user_id: int) -> None:
|
|||||||
key=_COOKIE_NAME,
|
key=_COOKIE_NAME,
|
||||||
value=token,
|
value=token,
|
||||||
httponly=True,
|
httponly=True,
|
||||||
secure=True, # send only over HTTPS (Nginx handles TLS in prod)
|
secure=_COOKIE_SECURE,
|
||||||
samesite="lax",
|
samesite="lax",
|
||||||
max_age=_COOKIE_MAX_AGE,
|
max_age=_COOKIE_MAX_AGE,
|
||||||
path="/",
|
path="/",
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Pull LMS images from GHCR and start the stack on a new machine.
|
||||||
|
# Usage: ./deploy.sh
|
||||||
|
# Requires: .env file with BACKEND_IMAGE, FRONTEND_IMAGE, POSTGRES_PASSWORD, JWT_SECRET_KEY
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
echo "❌ .env not found. Copy .env.example → .env and fill in the values."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
source .env
|
||||||
|
|
||||||
|
if [ -z "$POSTGRES_PASSWORD" ] || [ "$POSTGRES_PASSWORD" = "change_me_strong_password" ]; then
|
||||||
|
echo "❌ Set POSTGRES_PASSWORD in .env"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JWT_SECRET_KEY" ] || [ "$JWT_SECRET_KEY" = "change_me_generate_with_secrets_token_hex_32" ]; then
|
||||||
|
echo "❌ Set JWT_SECRET_KEY in .env"
|
||||||
|
echo " Generate: python3 -c \"import secrets; print(secrets.token_hex(32))\""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Login GHCR if token is provided
|
||||||
|
if [ -n "$GITHUB_TOKEN" ] && [ -n "$GITHUB_USER" ]; then
|
||||||
|
echo "🔐 Logging in to ghcr.io..."
|
||||||
|
echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$GITHUB_USER" --password-stdin
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "📦 Pulling images from GHCR..."
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
echo "🚀 Starting stack..."
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Running! Open http://localhost:${FRONTEND_PORT:-3000}"
|
||||||
|
docker compose ps
|
||||||
@@ -20,6 +20,7 @@ services:
|
|||||||
|
|
||||||
# ── FastAPI backend ───────────────────────────────────────────────────────────
|
# ── FastAPI backend ───────────────────────────────────────────────────────────
|
||||||
backend:
|
backend:
|
||||||
|
image: ${BACKEND_IMAGE:-lms-backend:latest}
|
||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./backend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
@@ -42,6 +43,7 @@ services:
|
|||||||
|
|
||||||
# ── Next.js frontend ──────────────────────────────────────────────────────────
|
# ── Next.js frontend ──────────────────────────────────────────────────────────
|
||||||
frontend:
|
frontend:
|
||||||
|
image: ${FRONTEND_IMAGE:-lms-frontend:latest}
|
||||||
build:
|
build:
|
||||||
context: ./frontend
|
context: ./frontend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ ENV NODE_ENV=production
|
|||||||
COPY --from=builder /app/public ./public
|
COPY --from=builder /app/public ./public
|
||||||
COPY --from=builder /app/.next/standalone ./
|
COPY --from=builder /app/.next/standalone ./
|
||||||
COPY --from=builder /app/.next/static ./.next/static
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
|
COPY --from=builder /app/next.config.js ./
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
|
|||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
declare module "fabric" {
|
||||||
|
export const fabric: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module "pdfjs-dist" {
|
||||||
|
export const GlobalWorkerOptions: {
|
||||||
|
workerSrc: string;
|
||||||
|
};
|
||||||
|
export const version: string;
|
||||||
|
export function getDocument(params: any): {
|
||||||
|
promise: Promise<any>;
|
||||||
|
};
|
||||||
|
}
|
||||||
Executable
+62
@@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Push LMS images to GitHub Container Registry (GHCR)
|
||||||
|
# Usage: ./push-ghcr.sh [tag]
|
||||||
|
# Reads GITHUB_USER and GITHUB_TOKEN from .env
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
|
# Load .env
|
||||||
|
if [ -f .env ]; then
|
||||||
|
export $(grep -v '^#' .env | grep -E 'GITHUB_USER|GITHUB_TOKEN' | xargs)
|
||||||
|
fi
|
||||||
|
|
||||||
|
TAG="${1:-latest}"
|
||||||
|
|
||||||
|
GITHUB_USER="${GITHUB_USER:?GITHUB_USER not set in .env}"
|
||||||
|
GITHUB_TOKEN="${GITHUB_TOKEN:?GITHUB_TOKEN not set in .env}"
|
||||||
|
|
||||||
|
BACKEND_IMAGE="ghcr.io/${GITHUB_USER}/lms-backend:${TAG}"
|
||||||
|
FRONTEND_IMAGE="ghcr.io/${GITHUB_USER}/lms-frontend:${TAG}"
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo " LMS → GHCR Push"
|
||||||
|
echo " Backend : $BACKEND_IMAGE"
|
||||||
|
echo " Frontend: $FRONTEND_IMAGE"
|
||||||
|
echo "========================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ── 1. Login to GHCR ──────────────────────────────────────────────────────────
|
||||||
|
echo "🔐 Logging in to ghcr.io ..."
|
||||||
|
echo "$GITHUB_TOKEN" | docker login ghcr.io -u "$GITHUB_USER" --password-stdin
|
||||||
|
|
||||||
|
# ── 2. Build images ───────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "🔨 Building images..."
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
docker compose build
|
||||||
|
|
||||||
|
# ── 3. Tag for GHCR ───────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "🏷 Tagging images..."
|
||||||
|
docker tag lms-backend:latest "$BACKEND_IMAGE"
|
||||||
|
docker tag lms-frontend:latest "$FRONTEND_IMAGE"
|
||||||
|
|
||||||
|
# ── 4. Push ───────────────────────────────────────────────────────────────────
|
||||||
|
echo ""
|
||||||
|
echo "⬆ Pushing to GHCR..."
|
||||||
|
docker push "$BACKEND_IMAGE"
|
||||||
|
docker push "$FRONTEND_IMAGE"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Done! Images pushed:"
|
||||||
|
echo " $BACKEND_IMAGE"
|
||||||
|
echo " $FRONTEND_IMAGE"
|
||||||
|
echo ""
|
||||||
|
echo "📋 Add these to .env on the target machine:"
|
||||||
|
echo " BACKEND_IMAGE=$BACKEND_IMAGE"
|
||||||
|
echo " FRONTEND_IMAGE=$FRONTEND_IMAGE"
|
||||||
|
echo ""
|
||||||
|
echo "🚀 On the target machine:"
|
||||||
|
echo " docker compose pull && docker compose up -d"
|
||||||
@@ -52,3 +52,85 @@ Let's build this step-by-step to avoid context limits.
|
|||||||
1. First, analyze this spec and confirm you understand.
|
1. First, analyze this spec and confirm you understand.
|
||||||
2. Provide the database schema models (SQLAlchemy or Prisma).
|
2. Provide the database schema models (SQLAlchemy or Prisma).
|
||||||
3. Wait for my confirmation before writing the Backend API routes.
|
3. Wait for my confirmation before writing the Backend API routes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. CI/CD — Push lên GitHub Container Registry (GHCR)
|
||||||
|
|
||||||
|
### 7.1. Yêu cầu
|
||||||
|
|
||||||
|
- **Docker** đã cài và đang chạy
|
||||||
|
- **GitHub Personal Access Token (PAT)** với quyền `write:packages` và `read:packages`
|
||||||
|
- Tạo tại: https://github.com/settings/tokens → *Generate new token (classic)*
|
||||||
|
- File `.env` đã được cấu hình (xem `.env.example`)
|
||||||
|
|
||||||
|
### 7.2. Cấu hình `.env`
|
||||||
|
|
||||||
|
Thêm các dòng sau vào file `.env` (file này đã được gitignore, **không commit**):
|
||||||
|
|
||||||
|
```env
|
||||||
|
GITHUB_USER=<github_username_của_bạn>
|
||||||
|
GITHUB_TOKEN=<personal_access_token>
|
||||||
|
BACKEND_IMAGE=ghcr.io/<github_username>/lms-backend:latest
|
||||||
|
FRONTEND_IMAGE=ghcr.io/<github_username>/lms-frontend:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3. Build & Push lên GHCR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x push-ghcr.sh
|
||||||
|
./push-ghcr.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Script sẽ tự động:
|
||||||
|
1. Đọc `GITHUB_USER` và `GITHUB_TOKEN` từ `.env`
|
||||||
|
2. Đăng nhập vào `ghcr.io`
|
||||||
|
3. Build cả hai image (`lms-backend`, `lms-frontend`) bằng `docker compose build`
|
||||||
|
4. Tag và push lên GHCR
|
||||||
|
|
||||||
|
Để push với tag cụ thể (ví dụ: version):
|
||||||
|
```bash
|
||||||
|
./push-ghcr.sh v1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.4. Deploy trên máy khác
|
||||||
|
|
||||||
|
Trên máy đích (server, VPS, máy tính khác):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Copy các file cần thiết
|
||||||
|
scp docker-compose.yml .env.example deploy.sh user@server:/opt/lms/
|
||||||
|
ssh user@server
|
||||||
|
|
||||||
|
# 2. Tạo .env từ example
|
||||||
|
cd /opt/lms
|
||||||
|
cp .env.example .env
|
||||||
|
# Điền các giá trị: POSTGRES_PASSWORD, JWT_SECRET_KEY, GITHUB_USER, GITHUB_TOKEN,
|
||||||
|
# BACKEND_IMAGE, FRONTEND_IMAGE
|
||||||
|
|
||||||
|
# 3. Chạy deploy
|
||||||
|
chmod +x deploy.sh
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Script `deploy.sh` sẽ:
|
||||||
|
1. Kiểm tra `.env` hợp lệ
|
||||||
|
2. Đăng nhập GHCR (nếu có token)
|
||||||
|
3. Pull image từ GHCR
|
||||||
|
4. Khởi động toàn bộ stack: `db`, `backend`, `frontend`
|
||||||
|
|
||||||
|
### 7.5. Kiểm tra packages trên GitHub
|
||||||
|
|
||||||
|
Sau khi push, image sẽ xuất hiện tại:
|
||||||
|
```
|
||||||
|
https://github.com/<github_username>?tab=packages
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Lưu ý:** Mặc định packages ở chế độ **Private**. Để máy khác pull mà không cần token, vào
|
||||||
|
> GitHub → Packages → tên package → *Package settings* → đổi visibility sang **Public**.
|
||||||
|
|
||||||
|
### 7.6. Sinh JWT Secret Key
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -c "import secrets; print(secrets.token_hex(32))"
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user