From c0f383f281778a58bc69dbc4d3477d0b39280866 Mon Sep 17 00:00:00 2001 From: d0zingcat Date: Mon, 12 Jan 2026 15:08:31 +0800 Subject: [PATCH 1/2] feat: add github docker pack Signed-off-by: d0zingcat --- .github/workflows/ci.yml | 49 ++++++++++++++++++++++++++++++++++++++++ README.md | 23 +++++++++++++++++++ apps/server/Dockerfile | 15 ++++++++++++ apps/web/Dockerfile | 21 +++++++++++++++++ docker-compose.yml | 23 +++++++++++++++++++ docs/copilot-context.md | 7 +++--- todo.md | 2 +- 7 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 apps/server/Dockerfile create mode 100644 apps/web/Dockerfile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c9c3d29 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,49 @@ +name: Build and Push Docker Images + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Server image + uses: docker/build-push-action@v5 + with: + context: . + file: apps/server/Dockerfile + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-server:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-server:${{ github.sha }} + + - name: Build and push Web image + uses: docker/build-push-action@v5 + with: + context: . + file: apps/web/Dockerfile + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-web:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-web:${{ github.sha }} diff --git a/README.md b/README.md index 100e977..3d8cd31 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,29 @@ cd apps/server && bun run db:push bun run dev ``` +### 3. Docker 部署 +项目支持使用 Docker Compose 快速部署: + +```bash +# 复制并填写环境变量 +cp apps/server/.env.example .env + +# 启动所有服务 (Postgres + Server + Web) +docker-compose up -d +``` + +--- + +## 🏗️ CI/CD + +项目通过 GitHub Actions 实现了自动化流水线: + +- **自动化构建**: 每次推送至 `main` 分支或提交 Pull Request 时,会自动触发 Docker 镜像构建。 +- **镜像仓库**: 构建生成的镜像会同步推送到 GitHub Container Registry (GHCR)。 +- **镜像路径**: + - `ghcr.io/${USER}/alert-message-center-server` + - `ghcr.io/${USER}/alert-message-center-web` + --- ## 📡 Webhook 使用指南 diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile new file mode 100644 index 0000000..fe00aa7 --- /dev/null +++ b/apps/server/Dockerfile @@ -0,0 +1,15 @@ +FROM oven/bun:1-alpine + +WORKDIR /app + +# Copy the entire project for monorepo context +COPY . . + +# Install dependencies +RUN bun install --frozen-lockfile + +WORKDIR /app/apps/server + +EXPOSE 3000 + +CMD ["bun", "run", "start"] diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile new file mode 100644 index 0000000..301c8bf --- /dev/null +++ b/apps/web/Dockerfile @@ -0,0 +1,21 @@ +# Build stage +FROM oven/bun:1-alpine AS builder + +WORKDIR /app + +# Copy the entire project +COPY . . + +# Install dependencies +RUN bun install --frozen-lockfile + +# Build the web app +WORKDIR /app/apps/web +RUN bun run build + +# Serve stage +FROM nginx:alpine +COPY --from=builder /app/apps/web/dist /usr/share/nginx/html +# Add a custom nginx config if needed to handle SPA routing, but for now default is okay +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker-compose.yml b/docker-compose.yml index b24ad5b..0a2801a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,27 @@ services: + server: + build: + context: . + dockerfile: apps/server/Dockerfile + ports: + - "3000:3000" + environment: + - DATABASE_URL=postgres://postgres:password@postgres:5432/alert_message_center + - FEISHU_APP_ID=${FEISHU_APP_ID} + - FEISHU_APP_SECRET=${FEISHU_APP_SECRET} + # ... other envs + depends_on: + - postgres + + web: + build: + context: . + dockerfile: apps/web/Dockerfile + ports: + - "80:80" + depends_on: + - server + postgres: image: postgres:17-alpine restart: always diff --git a/docs/copilot-context.md b/docs/copilot-context.md index acb91b8..345ffd6 100644 --- a/docs/copilot-context.md +++ b/docs/copilot-context.md @@ -125,7 +125,7 @@ The database schema is defined in `apps/server/src/db/schema.ts`. - [ ] **Message Preview**: Preview Feishu card JSON in the UI. - [ ] **History/Logs**: Keep a log of sent alerts for auditing. - [ ] **Retry Mechanism**: Handle Feishu API failures. -- [ ] **Deployment**: Dockerfile and deployment scripts. +- [x] **Deployment**: Dockerfile and deployment scripts. ## 7. Development Conventions @@ -135,7 +135,8 @@ The database schema is defined in `apps/server/src/db/schema.ts`. - **Type Safety**: strict TypeScript usage. Backend and Frontend share types via Hono RPC or shared interfaces. - **Environment Variables**: - `FEISHU_APP_ID`, `FEISHU_APP_SECRET`, `REDIRECT_URI`, `ADMIN_EMAILS`. -- **Administrators**: - - Configured via the `ADMIN_EMAILS` environment variable (comma-separated list of emails). +- **CI/CD**: + - GitHub Actions automates the build and push of Docker images to GitHub Container Registry (GHCR). + - Images are built for both `apps/server` (Bun) and `apps/web` (Nginx). diff --git a/todo.md b/todo.md index 9d6bbf5..353b022 100644 --- a/todo.md +++ b/todo.md @@ -21,5 +21,5 @@ - [x] **Admin Topic Management**: Approve, reject, and delete topics (with audit trail). - [x] **Personal Inbox**: Direct alert delivery bypassing topics. - [ ] **Retry Mechanism**: Handle Feishu API failures. -- [ ] **Deployment**: Dockerfile and deployment scripts. +- [x] **Deployment**: Dockerfile and CI/CD (GitHub Actions + GHCR). From 180f3cd825e8dfb8af926984b4ca65fcddca50cb Mon Sep 17 00:00:00 2001 From: d0zingcat Date: Tue, 13 Jan 2026 21:22:45 +0800 Subject: [PATCH 2/2] feat: add docker ci pack Signed-off-by: d0zingcat --- .env.example | 18 ++++++++++++++++++ Dockerfile | 26 ++++++++++++++++++++++++++ apps/server/Dockerfile | 15 --------------- apps/server/package.json | 2 +- apps/server/src/index.ts | 10 ++++++---- apps/web/.env.example | 2 ++ apps/web/Dockerfile | 21 --------------------- apps/web/package.json | 2 +- apps/web/vite.config.ts | 4 ++-- docker-compose.yml | 13 ++----------- package.json | 3 ++- 11 files changed, 60 insertions(+), 56 deletions(-) create mode 100644 .env.example create mode 100644 Dockerfile delete mode 100644 apps/server/Dockerfile create mode 100644 apps/web/.env.example delete mode 100644 apps/web/Dockerfile diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b5f9929 --- /dev/null +++ b/.env.example @@ -0,0 +1,18 @@ +# Database Configuration +# Use localhost for local 'bun run dev' +# docker-compose will override this with its own service name 'postgres' +DATABASE_URL=postgres://postgres:password@localhost:5432/alert_message_center + +# Feishu (Lark) App Configuration +# Make sure to ADD BOTH to your Feishu App Management console! +FEISHU_APP_ID=your_app_id +FEISHU_APP_SECRET=your_app_secret +FEISHU_VERIFICATION_TOKEN=your_verification_token +FEISHU_ENCRYPT_KEY=your_encrypt_key + +# Admin configuration (comma-separated emails) +ADMIN_EMAILS=admin@example.com + +# Optional: Frontend URL for CORS during local dev +FRONTEND_URL=http://localhost:3000 +REDIRECT_URI=http://localhost:3000/auth/callback \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3d0a432 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# Build stage for web +FROM oven/bun:1-alpine AS web-builder +WORKDIR /app +COPY . . +RUN bun install --frozen-lockfile +WORKDIR /app/apps/web +RUN bun run build + +# Final stage +FROM oven/bun:1-alpine +WORKDIR /app + +# Copy the entire project for monorepo context +COPY . . + +# Install dependencies for the server (and shared workspace if any) +RUN bun install --frozen-lockfile + +# Copy built web assets to server's public directory +COPY --from=web-builder /app/apps/web/dist /app/apps/server/public + +WORKDIR /app/apps/server + +EXPOSE 3000 + +CMD ["bun", "run", "start"] diff --git a/apps/server/Dockerfile b/apps/server/Dockerfile deleted file mode 100644 index fe00aa7..0000000 --- a/apps/server/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM oven/bun:1-alpine - -WORKDIR /app - -# Copy the entire project for monorepo context -COPY . . - -# Install dependencies -RUN bun install --frozen-lockfile - -WORKDIR /app/apps/server - -EXPOSE 3000 - -CMD ["bun", "run", "start"] diff --git a/apps/server/package.json b/apps/server/package.json index 4cea1e7..d0f4851 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,7 +2,7 @@ "name": "@alertmessagecenter/server", "version": "1.0.0", "scripts": { - "dev": "bun run --watch src/index.ts", + "dev": "bun run --env-file .env --watch src/index.ts", "start": "bun run src/index.ts", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 004a8bb..02751a6 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,5 +1,6 @@ import { Hono } from 'hono'; import { cors } from 'hono/cors'; +import { serveStatic } from 'hono/bun'; import { db } from './db'; import { topics } from './db/schema'; import webhook from './webhook'; @@ -14,14 +15,15 @@ app.use('/*', cors({ credentials: true, })); -app.get('/', (c) => { - return c.text('Alert Message Center API is running!'); -}); - +// API Routes const routes = app.route('/api/auth', auth) .route('/api', api) .route('/webhook', webhook); +// Serve static files (Frontend) +app.use('/*', serveStatic({ root: './public' })); +app.get('*', serveStatic({ path: './public/index.html' })); + app.onError((err, c) => { console.error(`[Global Error] ${c.req.method} ${c.req.url}:`, err); return c.json({ error: err.message || 'Internal Server Error' }, 500); diff --git a/apps/web/.env.example b/apps/web/.env.example new file mode 100644 index 0000000..d981975 --- /dev/null +++ b/apps/web/.env.example @@ -0,0 +1,2 @@ +# Backend API URL (for proxying) +VITE_API_URL=http://localhost:3000 diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile deleted file mode 100644 index 301c8bf..0000000 --- a/apps/web/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -# Build stage -FROM oven/bun:1-alpine AS builder - -WORKDIR /app - -# Copy the entire project -COPY . . - -# Install dependencies -RUN bun install --frozen-lockfile - -# Build the web app -WORKDIR /app/apps/web -RUN bun run build - -# Serve stage -FROM nginx:alpine -COPY --from=builder /app/apps/web/dist /usr/share/nginx/html -# Add a custom nginx config if needed to handle SPA routing, but for now default is okay -EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/web/package.json b/apps/web/package.json index a0dd2de..ecec8bd 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "bun run --env-file .env vite", "build": "tsc && vite build", "preview": "vite preview" }, diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index c3327c0..14e4692 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -13,11 +13,11 @@ export default defineConfig({ server: { proxy: { '/api': { - target: 'http://localhost:3000', + target: process.env.VITE_API_URL || 'http://localhost:3000', changeOrigin: true, }, '/webhook': { - target: 'http://localhost:3000', + target: process.env.VITE_API_URL || 'http://localhost:3000', changeOrigin: true, } } diff --git a/docker-compose.yml b/docker-compose.yml index 0a2801a..885d229 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,8 @@ services: - server: + app: build: context: . - dockerfile: apps/server/Dockerfile + dockerfile: Dockerfile ports: - "3000:3000" environment: @@ -13,15 +13,6 @@ services: depends_on: - postgres - web: - build: - context: . - dockerfile: apps/web/Dockerfile - ports: - - "80:80" - depends_on: - - server - postgres: image: postgres:17-alpine restart: always diff --git a/package.json b/package.json index a0d4b3c..a97bfaa 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,8 @@ ], "scripts": { "dev": "bun run --filter '*' dev", - "build": "bun run --filter '*' build" + "build": "bun run --filter '*' build", + "start": "bun run --filter '@alertmessagecenter/server' start" }, "devDependencies": { "bun-types": "latest"