diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6763bb9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,20 @@ +node_modules +dist +dist-ssr +.git +.gitea +.github +.idea +.vscode +.env +.env.* +!.env.example +*.local +.nitro +.tanstack +.wrangler +.output +.vinxi +__unconfig* +todos.json +README.md diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index c0813c9..a91063b 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,27 +1,92 @@ -name: Build +name: CI on: push: branches: - - proof + - main + workflow_dispatch: + +env: + REGISTRY: git.lukas-harat.com + IMAGE_NAME: ${{ github.repository }} permissions: contents: read + packages: write jobs: - build: + test: runs-on: ubuntu-latest steps: - name: Checkout - run: | - git init . - git config --global user.name "lukas" - git config --global user.password "ec61536af8db1a12ff8e79ce73b7f2036c94a723" - git remote add origin "https://git.lukas-harat.com/lukas/promo_steakhouse.git" - git fetch --depth=1 origin proof - git checkout -B proof FETCH_HEAD - + uses: actions/checkout@v4 - - \ No newline at end of file + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Typecheck + run: npx tsc --noEmit + + build: + needs: test + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push image + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max + + deploy: + needs: build + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Deploy to TrueNAS + env: + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }} + DEPLOY_USER: ${{ secrets.DEPLOY_USER }} + DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }} + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + IMAGE_TAG: ${{ github.sha }} + run: | + mkdir -p ~/.ssh + printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key + chmod 600 ~/.ssh/deploy_key + ssh-keyscan -p "${DEPLOY_PORT:-22}" -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts + + scp -i ~/.ssh/deploy_key -P "${DEPLOY_PORT:-22}" \ + docker-compose.prod.yml "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/docker-compose.yml" + + ssh -i ~/.ssh/deploy_key -p "${DEPLOY_PORT:-22}" "$DEPLOY_USER@$DEPLOY_HOST" \ + "cd $DEPLOY_PATH && IMAGE_TAG=$IMAGE_TAG docker compose pull && IMAGE_TAG=$IMAGE_TAG docker compose up -d && docker image prune -f" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b93b09b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# syntax=docker/dockerfile:1 + +FROM node:22-alpine AS builder +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . + +# Dummy values so the build-time env checks in src/db/index.ts and +# src/lib/auth-instance.ts don't throw while bundling. The real values are +# supplied at container runtime. +ENV DATABASE_URL=postgres://build:build@localhost:5432/build \ + BETTER_AUTH_SECRET=build-time-placeholder \ + BETTER_AUTH_URL=http://localhost:3000 + +RUN npm run build + +FROM node:22-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production + +# This build has no standalone Node server entrypoint — dist/server/server.js +# only exports a fetch handler. `vite preview` (via the tanstackStart plugin) +# is the supported way to serve it, and it re-resolves the app's router entry +# from src/ at startup, so the full source tree (not just dist/) has to ship. +COPY --from=builder /app ./ + +EXPOSE 3000 +CMD ["npm", "run", "preview", "--", "--host", "0.0.0.0", "--port", "3000"] diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..28d6a41 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,27 @@ +services: + app: + image: git.lukas-harat.com/lukas/promo_steakhouse:${IMAGE_TAG:-latest} + restart: unless-stopped + ports: + - '3000:3000' + environment: + DATABASE_URL: postgres://steakhouse:${POSTGRES_PASSWORD}@postgres:5432/steakhouse + BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET} + BETTER_AUTH_URL: ${BETTER_AUTH_URL} + RESEND_API_KEY: ${RESEND_API_KEY} + RESERVATIONS_FROM_EMAIL: ${RESERVATIONS_FROM_EMAIL} + depends_on: + - postgres + + postgres: + image: postgres:16-alpine + restart: unless-stopped + environment: + POSTGRES_USER: steakhouse + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: steakhouse + volumes: + - steakhouse-postgres-data:/var/lib/postgresql/data + +volumes: + steakhouse-postgres-data: