From c031540ef1be5369f38d6c89bae2b4767385504b Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:29:43 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20ci(nutriphi):=20add=20production?= =?UTF-8?q?=20deployment=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add backend Dockerfile with multi-stage build and health checks - Add web Dockerfile with SvelteKit static env vars - Add docker-entrypoint.sh for automatic DB migration - Add nutriphi-backend and nutriphi-web to docker-compose.macmini.yml - Add CI/CD detection and build jobs for nutriphi - Update CORS origins in mana-core-auth to include nutriphi.mana.how - Include nutriphi in deploy:landing:all script Ports: Backend 3023, Web 5189 Domain: nutriphi.mana.how / nutriphi-api.mana.how --- .github/workflows/ci.yml | 82 ++++++++++++++++++ apps/nutriphi/apps/backend/Dockerfile | 64 ++++++++++++++ .../apps/backend/docker-entrypoint.sh | 23 +++++ apps/nutriphi/apps/web/Dockerfile | 86 +++++++++++++++++++ docker-compose.macmini.yml | 57 +++++++++++- package.json | 2 +- 6 files changed, 312 insertions(+), 2 deletions(-) create mode 100644 apps/nutriphi/apps/backend/Dockerfile create mode 100644 apps/nutriphi/apps/backend/docker-entrypoint.sh create mode 100644 apps/nutriphi/apps/web/Dockerfile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c53a976e1..5cc4fbd98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,6 +66,8 @@ jobs: storage-backend: ${{ steps.changes.outputs.storage-backend }} storage-web: ${{ steps.changes.outputs.storage-web }} telegram-stats-bot: ${{ steps.changes.outputs.telegram-stats-bot }} + nutriphi-backend: ${{ steps.changes.outputs.nutriphi-backend }} + nutriphi-web: ${{ steps.changes.outputs.nutriphi-web }} any-changes: ${{ steps.changes.outputs.any-changes }} steps: - name: Checkout code @@ -96,6 +98,8 @@ jobs: echo "storage-backend=true" >> $GITHUB_OUTPUT echo "storage-web=true" >> $GITHUB_OUTPUT echo "telegram-stats-bot=true" >> $GITHUB_OUTPUT + echo "nutriphi-backend=true" >> $GITHUB_OUTPUT + echo "nutriphi-web=true" >> $GITHUB_OUTPUT echo "any-changes=true" >> $GITHUB_OUTPUT exit 0 fi @@ -130,6 +134,8 @@ jobs: echo "storage-backend=true" >> $GITHUB_OUTPUT echo "storage-web=true" >> $GITHUB_OUTPUT echo "telegram-stats-bot=true" >> $GITHUB_OUTPUT + echo "nutriphi-backend=true" >> $GITHUB_OUTPUT + echo "nutriphi-web=true" >> $GITHUB_OUTPUT echo "any-changes=true" >> $GITHUB_OUTPUT exit 0 fi @@ -297,6 +303,22 @@ jobs: echo "telegram-stats-bot=false" >> $GITHUB_OUTPUT fi + # nutriphi-backend + NUTRIPHI_BACKEND_CHANGED=$(check_pattern "apps/nutriphi/apps/backend/|apps/nutriphi/packages/") + if [ "$COMMON_CHANGED" == "true" ] || [ "$SHARED_AUTH_CHANGED" == "true" ] || [ "$NUTRIPHI_BACKEND_CHANGED" == "true" ]; then + echo "nutriphi-backend=true" >> $GITHUB_OUTPUT + else + echo "nutriphi-backend=false" >> $GITHUB_OUTPUT + fi + + # nutriphi-web + NUTRIPHI_WEB_CHANGED=$(check_pattern "apps/nutriphi/apps/web/|apps/nutriphi/packages/") + if [ "$COMMON_CHANGED" == "true" ] || [ "$SHARED_AUTH_CHANGED" == "true" ] || [ "$SHARED_UI_CHANGED" == "true" ] || [ "$SHARED_WEB_CHANGED" == "true" ] || [ "$NUTRIPHI_WEB_CHANGED" == "true" ]; then + echo "nutriphi-web=true" >> $GITHUB_OUTPUT + else + echo "nutriphi-web=false" >> $GITHUB_OUTPUT + fi + # Check if any service needs building if grep -q "=true" $GITHUB_OUTPUT; then echo "any-changes=true" >> $GITHUB_OUTPUT @@ -327,6 +349,8 @@ jobs: echo "| storage-backend | ${{ steps.changes.outputs.storage-backend }} |" >> $GITHUB_STEP_SUMMARY echo "| storage-web | ${{ steps.changes.outputs.storage-web }} |" >> $GITHUB_STEP_SUMMARY echo "| telegram-stats-bot | ${{ steps.changes.outputs.telegram-stats-bot }} |" >> $GITHUB_STEP_SUMMARY + echo "| nutriphi-backend | ${{ steps.changes.outputs.nutriphi-backend }} |" >> $GITHUB_STEP_SUMMARY + echo "| nutriphi-web | ${{ steps.changes.outputs.nutriphi-web }} |" >> $GITHUB_STEP_SUMMARY # =========================================== # Validation job - runs on PRs @@ -858,3 +882,61 @@ jobs: tags: ${{ steps.meta.outputs.tags }} cache-from: type=gha cache-to: type=gha,mode=max + + build-nutriphi-backend: + name: Build nutriphi-backend + runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.nutriphi-backend == 'true' + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/metadata-action@v5 + id: meta + with: + images: ghcr.io/${{ github.repository_owner }}/nutriphi-backend + tags: type=raw,value=latest + - uses: docker/build-push-action@v5 + with: + context: . + file: apps/nutriphi/apps/backend/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + cache-from: type=gha + cache-to: type=gha,mode=max + + build-nutriphi-web: + name: Build nutriphi-web + runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.nutriphi-web == 'true' + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + - uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - uses: docker/metadata-action@v5 + id: meta + with: + images: ghcr.io/${{ github.repository_owner }}/nutriphi-web + tags: type=raw,value=latest + - uses: docker/build-push-action@v5 + with: + context: . + file: apps/nutriphi/apps/web/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/apps/nutriphi/apps/backend/Dockerfile b/apps/nutriphi/apps/backend/Dockerfile new file mode 100644 index 000000000..60bfdc807 --- /dev/null +++ b/apps/nutriphi/apps/backend/Dockerfile @@ -0,0 +1,64 @@ +# Build stage +FROM node:20-alpine AS builder + +# Install pnpm +RUN corepack enable && corepack prepare pnpm@9.15.0 --activate + +WORKDIR /app + +# Copy root workspace files +COPY pnpm-workspace.yaml ./ +COPY package.json ./ +COPY pnpm-lock.yaml ./ + +# Copy shared packages +COPY packages/shared-nestjs-auth ./packages/shared-nestjs-auth + +# Copy nutriphi packages and backend +COPY apps/nutriphi/packages ./apps/nutriphi/packages +COPY apps/nutriphi/apps/backend ./apps/nutriphi/apps/backend + +# Install dependencies +RUN pnpm install --frozen-lockfile + +# Build shared packages first +WORKDIR /app/packages/shared-nestjs-auth +RUN pnpm build + +# Build the backend +WORKDIR /app/apps/nutriphi/apps/backend +RUN pnpm build + +# Production stage +FROM node:20-alpine AS production + +# Install pnpm and postgresql-client for health checks +RUN corepack enable && corepack prepare pnpm@9.15.0 --activate \ + && apk add --no-cache postgresql-client + +WORKDIR /app + +# Copy everything from builder (including node_modules) +COPY --from=builder /app/pnpm-workspace.yaml ./ +COPY --from=builder /app/package.json ./ +COPY --from=builder /app/pnpm-lock.yaml ./ +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/packages ./packages +COPY --from=builder /app/apps/nutriphi ./apps/nutriphi + +# Copy entrypoint script +COPY apps/nutriphi/apps/backend/docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +WORKDIR /app/apps/nutriphi/apps/backend + +# Expose port +EXPOSE 3023 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:3023/api/v1/health || exit 1 + +# Run entrypoint script +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["node", "dist/main.js"] diff --git a/apps/nutriphi/apps/backend/docker-entrypoint.sh b/apps/nutriphi/apps/backend/docker-entrypoint.sh new file mode 100644 index 000000000..a50094fdb --- /dev/null +++ b/apps/nutriphi/apps/backend/docker-entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/sh +set -e + +echo "=== NutriPhi Backend Entrypoint ===" + +# Wait for PostgreSQL to be ready +echo "Waiting for PostgreSQL..." +until pg_isready -h ${DB_HOST:-postgres} -p ${DB_PORT:-5432} -U ${DB_USER:-postgres} 2>/dev/null; do + echo "PostgreSQL is unavailable - sleeping" + sleep 2 +done +echo "PostgreSQL is up!" + +cd /app/apps/nutriphi/apps/backend + +# Run schema push +echo "Pushing database schema..." +npx drizzle-kit push --force +echo "Schema push completed!" + +# Execute the main command +echo "Starting application..." +exec "$@" diff --git a/apps/nutriphi/apps/web/Dockerfile b/apps/nutriphi/apps/web/Dockerfile new file mode 100644 index 000000000..275e11200 --- /dev/null +++ b/apps/nutriphi/apps/web/Dockerfile @@ -0,0 +1,86 @@ +# Build stage +FROM node:20-alpine AS builder + +# Build arguments for SvelteKit static env vars +ARG PUBLIC_BACKEND_URL=http://nutriphi-backend:3023 +ARG PUBLIC_MANA_CORE_AUTH_URL=http://mana-core-auth:3001 + +# Set as environment variables for build +ENV PUBLIC_BACKEND_URL=$PUBLIC_BACKEND_URL +ENV PUBLIC_MANA_CORE_AUTH_URL=$PUBLIC_MANA_CORE_AUTH_URL + +# Install pnpm +RUN corepack enable && corepack prepare pnpm@9.15.0 --activate + +WORKDIR /app + +# Copy root workspace files +COPY pnpm-workspace.yaml ./ +COPY package.json ./ +COPY pnpm-lock.yaml ./ + +# Copy shared packages needed by nutriphi web +COPY packages/shared-types ./packages/shared-types +COPY packages/shared-auth ./packages/shared-auth +COPY packages/shared-auth-ui ./packages/shared-auth-ui +COPY packages/shared-branding ./packages/shared-branding +COPY packages/shared-feedback-service ./packages/shared-feedback-service +COPY packages/shared-feedback-types ./packages/shared-feedback-types +COPY packages/shared-feedback-ui ./packages/shared-feedback-ui +COPY packages/shared-i18n ./packages/shared-i18n +COPY packages/shared-icons ./packages/shared-icons +COPY packages/shared-tailwind ./packages/shared-tailwind +COPY packages/shared-theme ./packages/shared-theme +COPY packages/shared-theme-ui ./packages/shared-theme-ui +COPY packages/shared-subscription-types ./packages/shared-subscription-types +COPY packages/shared-subscription-ui ./packages/shared-subscription-ui +COPY packages/shared-profile-ui ./packages/shared-profile-ui +COPY packages/shared-ui ./packages/shared-ui +COPY packages/shared-utils ./packages/shared-utils + +# Copy nutriphi packages and web +COPY apps/nutriphi/packages ./apps/nutriphi/packages +COPY apps/nutriphi/apps/web ./apps/nutriphi/apps/web + +# Install dependencies +RUN pnpm install --frozen-lockfile + +# Build shared packages that need building +WORKDIR /app/packages/shared-auth +RUN pnpm build || true + +# Build the web app +WORKDIR /app/apps/nutriphi/apps/web +RUN pnpm exec svelte-kit sync +RUN pnpm build + +# Production stage +FROM node:20-alpine AS production + +# Keep same directory structure as builder so pnpm symlinks resolve correctly +WORKDIR /app/apps/nutriphi/apps/web + +# Copy the pnpm store that symlinks point to (at /app/node_modules/.pnpm) +COPY --from=builder /app/node_modules/.pnpm /app/node_modules/.pnpm + +# Copy the app's node_modules (contains symlinks to the pnpm store) +COPY --from=builder /app/apps/nutriphi/apps/web/node_modules ./node_modules + +# Copy built application +COPY --from=builder /app/apps/nutriphi/apps/web/build ./build +COPY --from=builder /app/apps/nutriphi/apps/web/package.json ./ + +# Expose port +EXPOSE 5189 + +# Set environment variables +ENV NODE_ENV=production +ENV PORT=5189 +ENV HOST=0.0.0.0 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:5189/health || exit 1 + +# Run the app +CMD ["node", "build"] diff --git a/docker-compose.macmini.yml b/docker-compose.macmini.yml index 3121fa5b2..0dc3a0c4e 100644 --- a/docker-compose.macmini.yml +++ b/docker-compose.macmini.yml @@ -89,7 +89,7 @@ services: SMTP_USER: ${SMTP_USER:-94cde5002@smtp-brevo.com} SMTP_PASSWORD: ${SMTP_PASSWORD} SMTP_FROM: ManaCore - CORS_ORIGINS: https://mana.how,https://chat.mana.how,https://todo.mana.how,https://calendar.mana.how,https://clock.mana.how,https://contacts.mana.how,https://storage.mana.how,https://presi.mana.how + CORS_ORIGINS: https://mana.how,https://chat.mana.how,https://todo.mana.how,https://calendar.mana.how,https://clock.mana.how,https://contacts.mana.how,https://storage.mana.how,https://presi.mana.how,https://nutriphi.mana.how # DuckDB Analytics (Business Metrics) DUCKDB_PATH: /data/analytics/metrics.duckdb volumes: @@ -534,6 +534,61 @@ services: retries: 3 start_period: 40s + # ============================================ + # NutriPhi App (AI Nutrition Tracking) + # ============================================ + + nutriphi-backend: + image: ghcr.io/memo-2023/nutriphi-backend:latest + container_name: nutriphi-backend + restart: always + depends_on: + mana-core-auth: + condition: service_healthy + postgres: + condition: service_healthy + environment: + NODE_ENV: production + PORT: 3023 + DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/nutriphi + DB_HOST: postgres + DB_PORT: 5432 + DB_USER: postgres + MANA_CORE_AUTH_URL: http://mana-core-auth:3001 + GEMINI_API_KEY: ${GEMINI_API_KEY:-} + CORS_ORIGINS: https://nutriphi.mana.how,https://mana.how + ports: + - "3023:3023" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3023/api/v1/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + nutriphi-web: + image: ghcr.io/memo-2023/nutriphi-web:latest + container_name: nutriphi-web + restart: always + depends_on: + nutriphi-backend: + condition: service_healthy + environment: + NODE_ENV: production + PORT: 5189 + PUBLIC_BACKEND_URL: http://nutriphi-backend:3023 + PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001 + PUBLIC_BACKEND_URL_CLIENT: https://nutriphi-api.mana.how + PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how + ports: + - "5189:5189" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5189/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + # ============================================ # Monitoring Stack # ============================================ diff --git a/package.json b/package.json index f269a2421..9785afb43 100644 --- a/package.json +++ b/package.json @@ -206,7 +206,7 @@ "deploy:landing:clock": "pnpm --filter @clock/landing build && npx wrangler pages deploy apps/clock/apps/landing/dist --project-name=clocks-landing", "deploy:landing:mail": "pnpm --filter @mail/landing build && npx wrangler pages deploy apps/mail/apps/landing/dist --project-name=mail-landing", "deploy:landing:moodlit": "pnpm --filter @moodlit/landing build && npx wrangler pages deploy apps/moodlit/apps/landing/dist --project-name=moodlit-landing", - "deploy:landing:all": "pnpm deploy:landing:calendar && pnpm deploy:landing:chat && pnpm deploy:landing:picture && pnpm deploy:landing:manacore && pnpm deploy:landing:manadeck && pnpm deploy:landing:zitare && pnpm deploy:landing:presi && pnpm deploy:landing:clock && pnpm deploy:landing:mail", + "deploy:landing:all": "pnpm deploy:landing:calendar && pnpm deploy:landing:chat && pnpm deploy:landing:picture && pnpm deploy:landing:manacore && pnpm deploy:landing:manadeck && pnpm deploy:landing:zitare && pnpm deploy:landing:presi && pnpm deploy:landing:clock && pnpm deploy:landing:mail && pnpm deploy:landing:nutriphi", "cf:login": "npx wrangler login", "cf:projects:list": "npx wrangler pages project list", "cf:projects:create": "echo 'Creating Cloudflare Pages projects...' && npx wrangler pages project create chat-landing --production-branch=main && npx wrangler pages project create picture-landing --production-branch=main && npx wrangler pages project create manacore-landing --production-branch=main && npx wrangler pages project create manadeck-landing --production-branch=main && npx wrangler pages project create zitare-landing --production-branch=main",