Skip to content
This repository was archived by the owner on Jul 7, 2026. It is now read-only.

docs: sync documentation to current architecture; add agent-first docs #42

docs: sync documentation to current architecture; add agent-first docs

docs: sync documentation to current architecture; add agent-first docs #42

Workflow file for this run

name: Build & Deploy
on:
push:
branches: [master]
env:
REGISTRY: ghcr.io
WEB_IMAGE: ghcr.io/chanmeng666/fanfic-lab/web
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push Web image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile.web
push: true
tags: |
${{ env.WEB_IMAGE }}:${{ github.sha }}
${{ env.WEB_IMAGE }}:latest
cache-from: type=gha,scope=web
cache-to: type=gha,mode=max,scope=web
build-args: |
NEXT_PUBLIC_STACK_PROJECT_ID=${{ secrets.NEXT_PUBLIC_STACK_PROJECT_ID }}
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY=${{ secrets.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY }}
STACK_SECRET_SERVER_KEY=${{ secrets.STACK_SECRET_SERVER_KEY }}
DATABASE_URL=${{ secrets.DATABASE_URL }}
REDIS_URL=${{ secrets.REDIS_URL }}
OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}
LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}
CLOUDINARY_CLOUD_NAME=${{ secrets.CLOUDINARY_CLOUD_NAME }}
CLOUDINARY_API_KEY=${{ secrets.CLOUDINARY_API_KEY }}
CLOUDINARY_API_SECRET=${{ secrets.CLOUDINARY_API_SECRET }}
ADMIN_SECRET=${{ secrets.ADMIN_SECRET }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy to VPS via SSH
uses: appleboy/ssh-action@v1
env:
WEB_TAG: ${{ env.WEB_IMAGE }}:${{ github.sha }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_ACTOR: ${{ github.actor }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
REDIS_URL: ${{ secrets.REDIS_URL }}
STACK_SECRET_SERVER_KEY: ${{ secrets.STACK_SECRET_SERVER_KEY }}
NEXT_PUBLIC_STACK_PROJECT_ID: ${{ secrets.NEXT_PUBLIC_STACK_PROJECT_ID }}
NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY: ${{ secrets.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY }}
CLOUDINARY_CLOUD_NAME: ${{ secrets.CLOUDINARY_CLOUD_NAME }}
CLOUDINARY_API_KEY: ${{ secrets.CLOUDINARY_API_KEY }}
CLOUDINARY_API_SECRET: ${{ secrets.CLOUDINARY_API_SECRET }}
ADMIN_SECRET: ${{ secrets.ADMIN_SECRET }}
with:
host: ${{ secrets.VPS_HOST }}
username: root
key: ${{ secrets.VPS_SSH_KEY }}
command_timeout: 20m
envs: WEB_TAG,GH_TOKEN,GH_ACTOR,OPENAI_API_KEY,LANGSMITH_API_KEY,DATABASE_URL,REDIS_URL,STACK_SECRET_SERVER_KEY,NEXT_PUBLIC_STACK_PROJECT_ID,NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY,CLOUDINARY_CLOUD_NAME,CLOUDINARY_API_KEY,CLOUDINARY_API_SECRET,ADMIN_SECRET
script: |
set -e
# Login to GHCR
echo "$GH_TOKEN" | docker login ghcr.io -u "$GH_ACTOR" --password-stdin
# Pull new image (old container keeps running until swap)
docker pull "$WEB_TAG"
# Stop old containers gracefully (agent container is retired — clean it up too)
docker stop agent-dreamwriter web-dreamwriter 2>/dev/null || true
docker rm agent-dreamwriter web-dreamwriter 2>/dev/null || true
# Also stop Coolify-managed containers if they exist
docker ps --filter "name=web-wea94e" --filter "name=agent-wea94e" -q | xargs -r docker stop 2>/dev/null || true
# Start web (DreamWriter agent runs in-process) with Traefik labels for reverse proxy
docker run -d \
--name web-dreamwriter \
--network coolify \
--restart unless-stopped \
-l "traefik.enable=true" \
-l "traefik.http.routers.dreamwriter.rule=Host(\`fanfic-lab.tech\`) || Host(\`www.fanfic-lab.tech\`)" \
-l "traefik.http.routers.dreamwriter.entrypoints=https" \
-l "traefik.http.routers.dreamwriter.tls.certresolver=letsencrypt" \
-l "traefik.http.services.dreamwriter.loadbalancer.server.port=3000" \
-e NODE_ENV=production \
-e DATABASE_URL="${DATABASE_URL}" \
-e REDIS_URL="${REDIS_URL}" \
-e OPENAI_API_KEY="${OPENAI_API_KEY}" \
-e LANGSMITH_API_KEY="${LANGSMITH_API_KEY}" \
-e STACK_SECRET_SERVER_KEY="${STACK_SECRET_SERVER_KEY}" \
-e NEXT_PUBLIC_STACK_PROJECT_ID="${NEXT_PUBLIC_STACK_PROJECT_ID}" \
-e NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY="${NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY}" \
-e CLOUDINARY_CLOUD_NAME="${CLOUDINARY_CLOUD_NAME}" \
-e CLOUDINARY_API_KEY="${CLOUDINARY_API_KEY}" \
-e CLOUDINARY_API_SECRET="${CLOUDINARY_API_SECRET}" \
-e ADMIN_SECRET="${ADMIN_SECRET}" \
"$WEB_TAG"
echo "Deployment complete!"