feat: add Dockerfiles and workflow configurations for CRUD, Ingest, and Web APIs
release-web / release (push) Has been cancelled

This commit is contained in:
marco.chan committed 2026-09-04 12:38:53 +08:00
1 parent d3b6c5032f
commit d8b7b9735b
7 files changed
+334

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
# Unified production environment template
# Copy and fill values with your real production endpoints/secrets.
NODE_ENV=production
# Shared infrastructure
DATABASE_URL=postgres://user:password@db-host:5432/app
MONGO_URL=mongodb://user:password@mongo-host:27017/app
REDIS_URL=redis://redis-host:6379
# API ports (optional, if your runtime uses explicit ports)
CRUD_PORT=3000
INGEST_PORT=3001
# Service-specific prefixes used by release filtering
CRUD_HOST=0.0.0.0
INGEST_HOST=0.0.0.0
# Frontend build/runtime values
VITE_API_BASE_URL=https://api.example.com
VITE_INGEST_BASE_URL=https://ingest.example.com
+72
View File
@@ -0,0 +1,72 @@
name: release-crud-api
on:
push:
tags:
- 'crud-api/v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from tag
id: meta
shell: bash
run: |
set -euo pipefail
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#crud-api/v}"
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
- name: Build Docker image (root context)
shell: bash
run: |
set -euo pipefail
docker build \
--file apps/crud-api/Dockerfile \
--tag crud-api:${{ steps.meta.outputs.version }} \
.
- name: Package tar + filtered env
id: bundle
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.meta.outputs.version }}"
OUT_DIR="dist/release"
TAR_PATH="${OUT_DIR}/crud-api-${VERSION}.tar"
ZIP_PATH="${OUT_DIR}/crud-api-${VERSION}.zip"
ENV_PATH="${OUT_DIR}/.env"
mkdir -p "${OUT_DIR}"
docker save --output "${TAR_PATH}" "crud-api:${VERSION}"
if [ ! -f .env.production ]; then
echo ".env.production is missing at repository root" >&2
exit 1
fi
# Keep only variables needed by crud-api deployment.
grep -E '^(NODE_ENV|CRUD_|DATABASE_URL|REDIS_URL)=' .env.production > "${ENV_PATH}"
zip -j "${ZIP_PATH}" "${TAR_PATH}" "${ENV_PATH}"
echo "zip_path=${ZIP_PATH}" >> "${GITHUB_OUTPUT}"
- name: Create Gitea release with artifact
uses: https://gitea.com/actions/gitea-release-action@v1
with:
token: ${{ secrets.RELEASE_TOKEN }}
tag_name: ${{ github.ref_name }}
name: crud-api v${{ steps.meta.outputs.version }}
body: |
Automated release bundle for crud-api.
Includes:
- Docker image tar
- filtered .env for deploy
files: |
${{ steps.bundle.outputs.zip_path }}
+72
View File
@@ -0,0 +1,72 @@
name: release-ingest-api
on:
push:
tags:
- 'ingest-api/v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from tag
id: meta
shell: bash
run: |
set -euo pipefail
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#ingest-api/v}"
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
- name: Build Docker image (root context)
shell: bash
run: |
set -euo pipefail
docker build \
--file apps/ingest-api/Dockerfile \
--tag ingest-api:${{ steps.meta.outputs.version }} \
.
- name: Package tar + filtered env
id: bundle
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.meta.outputs.version }}"
OUT_DIR="dist/release"
TAR_PATH="${OUT_DIR}/ingest-api-${VERSION}.tar"
ZIP_PATH="${OUT_DIR}/ingest-api-${VERSION}.zip"
ENV_PATH="${OUT_DIR}/.env"
mkdir -p "${OUT_DIR}"
docker save --output "${TAR_PATH}" "ingest-api:${VERSION}"
if [ ! -f .env.production ]; then
echo ".env.production is missing at repository root" >&2
exit 1
fi
# Keep only variables needed by ingest-api deployment.
grep -E '^(NODE_ENV|INGEST_|DATABASE_URL|MONGO_URL|REDIS_URL)=' .env.production > "${ENV_PATH}"
zip -j "${ZIP_PATH}" "${TAR_PATH}" "${ENV_PATH}"
echo "zip_path=${ZIP_PATH}" >> "${GITHUB_OUTPUT}"
- name: Create Gitea release with artifact
uses: https://gitea.com/actions/gitea-release-action@v1
with:
token: ${{ secrets.RELEASE_TOKEN }}
tag_name: ${{ github.ref_name }}
name: ingest-api v${{ steps.meta.outputs.version }}
body: |
Automated release bundle for ingest-api.
Includes:
- Docker image tar
- filtered .env for deploy
files: |
${{ steps.bundle.outputs.zip_path }}
+72
View File
@@ -0,0 +1,72 @@
name: release-web
on:
push:
tags:
- 'web/v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from tag
id: meta
shell: bash
run: |
set -euo pipefail
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#web/v}"
echo "version=${VERSION}" >> "${GITHUB_OUTPUT}"
- name: Build Docker image (root context)
shell: bash
run: |
set -euo pipefail
docker build \
--file apps/web/Dockerfile \
--tag web:${{ steps.meta.outputs.version }} \
.
- name: Package tar + filtered env
id: bundle
shell: bash
run: |
set -euo pipefail
VERSION="${{ steps.meta.outputs.version }}"
OUT_DIR="dist/release"
TAR_PATH="${OUT_DIR}/web-${VERSION}.tar"
ZIP_PATH="${OUT_DIR}/web-${VERSION}.zip"
ENV_PATH="${OUT_DIR}/.env"
mkdir -p "${OUT_DIR}"
docker save --output "${TAR_PATH}" "web:${VERSION}"
if [ ! -f .env.production ]; then
echo ".env.production is missing at repository root" >&2
exit 1
fi
# Keep only variables needed by web deployment.
grep -E '^(NODE_ENV|VITE_)=' .env.production > "${ENV_PATH}"
zip -j "${ZIP_PATH}" "${TAR_PATH}" "${ENV_PATH}"
echo "zip_path=${ZIP_PATH}" >> "${GITHUB_OUTPUT}"
- name: Create Gitea release with artifact
uses: https://gitea.com/actions/gitea-release-action@v1
with:
token: ${{ secrets.RELEASE_TOKEN }}
tag_name: ${{ github.ref_name }}
name: web v${{ steps.meta.outputs.version }}
body: |
Automated release bundle for web.
Includes:
- Docker image tar
- filtered .env for deploy
files: |
${{ steps.bundle.outputs.zip_path }}
+36
View File
@@ -0,0 +1,36 @@
# syntax=docker/dockerfile:1.7
# Build from the monorepo root context so this image can use:
# - apps/crud-api
# - packages/contracts
FROM node:20-alpine AS base
WORKDIR /workspace
RUN corepack enable
FROM base AS deps
COPY package.json yarn.lock .yarnrc.yml ./
COPY .yarn/ ./.yarn/
COPY apps/crud-api/package.json ./apps/crud-api/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
# Use node_modules inside the container for predictable runtime behavior.
RUN YARN_NODE_LINKER=node-modules yarn install --immutable
FROM deps AS build
COPY apps/crud-api ./apps/crud-api
COPY packages/contracts ./packages/contracts
RUN yarn workspace crud-api build
FROM node:20-alpine AS runtime
WORKDIR /workspace
ENV NODE_ENV=production
RUN corepack enable
COPY --from=build /workspace/package.json /workspace/yarn.lock /workspace/.yarnrc.yml ./
COPY --from=build /workspace/.yarn ./.yarn
COPY --from=build /workspace/node_modules ./node_modules
COPY --from=build /workspace/apps/crud-api ./apps/crud-api
COPY --from=build /workspace/packages/contracts ./packages/contracts
EXPOSE 3000
CMD ["yarn", "workspace", "crud-api", "start"]
+36
View File
@@ -0,0 +1,36 @@
# syntax=docker/dockerfile:1.7
# Build from the monorepo root context so this image can use:
# - apps/ingest-api
# - packages/contracts
FROM node:20-alpine AS base
WORKDIR /workspace
RUN corepack enable
FROM base AS deps
COPY package.json yarn.lock .yarnrc.yml ./
COPY .yarn/ ./.yarn/
COPY apps/ingest-api/package.json ./apps/ingest-api/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
# Use node_modules inside the container for predictable runtime behavior.
RUN YARN_NODE_LINKER=node-modules yarn install --immutable
FROM deps AS build
COPY apps/ingest-api ./apps/ingest-api
COPY packages/contracts ./packages/contracts
RUN yarn workspace ingest-api build
FROM node:20-alpine AS runtime
WORKDIR /workspace
ENV NODE_ENV=production
RUN corepack enable
COPY --from=build /workspace/package.json /workspace/yarn.lock /workspace/.yarnrc.yml ./
COPY --from=build /workspace/.yarn ./.yarn
COPY --from=build /workspace/node_modules ./node_modules
COPY --from=build /workspace/apps/ingest-api ./apps/ingest-api
COPY --from=build /workspace/packages/contracts ./packages/contracts
EXPOSE 3001
CMD ["yarn", "workspace", "ingest-api", "start"]
+25
View File
@@ -0,0 +1,25 @@
# syntax=docker/dockerfile:1.7
# Build from the monorepo root context so this image can use:
# - apps/web
# - packages/contracts
FROM node:20-alpine AS base
WORKDIR /workspace
RUN corepack enable
FROM base AS deps
COPY package.json yarn.lock .yarnrc.yml ./
COPY .yarn/ ./.yarn/
COPY apps/web/package.json ./apps/web/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
RUN YARN_NODE_LINKER=node-modules yarn install --immutable
FROM deps AS build
COPY apps/web ./apps/web
COPY packages/contracts ./packages/contracts
RUN yarn workspace web build
FROM nginx:1.27-alpine AS runtime
COPY --from=build /workspace/apps/web/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]