From 5ce4e42c205cfaf621f2e2367d54f1b0fad116e6 Mon Sep 17 00:00:00 2001 From: Till-JS <101404291+Till-JS@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:21:19 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20feat(photos):=20add=20Docker=20d?= =?UTF-8?q?eployment=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Dockerfile for photos-backend (port 3039) - Add Dockerfile for photos-web (port 5019) - Add docker-entrypoint.sh for database migrations - Add health endpoint for photos-web - Add photos services to docker-compose.macmini.yml - Update CORS_ORIGINS for mana-auth and mana-media - Update CLAUDE.md with production URLs Co-Authored-By: Claude Opus 4.5 --- apps/photos/CLAUDE.md | 10 +- apps/photos/apps/backend/Dockerfile | 88 +++++++++++++++ apps/photos/apps/backend/docker-entrypoint.sh | 9 ++ apps/photos/apps/web/Dockerfile | 101 ++++++++++++++++++ .../apps/web/src/routes/health/+server.ts | 10 ++ docker-compose.macmini.yml | 67 +++++++++++- 6 files changed, 278 insertions(+), 7 deletions(-) create mode 100644 apps/photos/apps/backend/Dockerfile create mode 100644 apps/photos/apps/backend/docker-entrypoint.sh create mode 100644 apps/photos/apps/web/Dockerfile create mode 100644 apps/photos/apps/web/src/routes/health/+server.ts diff --git a/apps/photos/CLAUDE.md b/apps/photos/CLAUDE.md index 489e8bb2d..7e8b67b80 100644 --- a/apps/photos/CLAUDE.md +++ b/apps/photos/CLAUDE.md @@ -4,10 +4,10 @@ **Photos** is a unified photo gallery application for the ManaCore ecosystem. It aggregates photos from all apps (Picture, Chat, Contacts, NutriPhi, etc.) via the mana-media service, providing a central place to view, organize, and manage photos. -| App | Port | URL | -|-----|------|-----| -| Backend | 3019 | http://localhost:3019 | -| Web App | 5189 | http://localhost:5189 | +| App | Dev Port | Prod Port | Prod URL | +|-----|----------|-----------|----------| +| Backend | 3019 | 3039 | https://photos-api.mana.how | +| Web App | 5189 | 5019 | https://photos.mana.how | ## Project Structure @@ -15,7 +15,7 @@ apps/photos/ ├── apps/ │ ├── backend/ # NestJS API server (@photos/backend) -│ └── web/ # SvelteKit web application (@photos/web) [TODO] +│ └── web/ # SvelteKit web application (@photos/web) ├── packages/ │ └── shared/ # Shared types (@photos/shared) ├── package.json diff --git a/apps/photos/apps/backend/Dockerfile b/apps/photos/apps/backend/Dockerfile new file mode 100644 index 000000000..c389fa117 --- /dev/null +++ b/apps/photos/apps/backend/Dockerfile @@ -0,0 +1,88 @@ +# 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 (all required dependencies) +COPY packages/shared-errors ./packages/shared-errors +COPY packages/shared-nestjs-auth ./packages/shared-nestjs-auth +COPY packages/shared-nestjs-health ./packages/shared-nestjs-health +COPY packages/shared-nestjs-metrics ./packages/shared-nestjs-metrics +COPY packages/shared-nestjs-setup ./packages/shared-nestjs-setup +COPY packages/shared-tsconfig ./packages/shared-tsconfig +COPY packages/mana-core-nestjs-integration ./packages/mana-core-nestjs-integration +COPY packages/shared-drizzle-config ./packages/shared-drizzle-config + +# Copy photos shared package +COPY apps/photos/packages/shared ./apps/photos/packages/shared + +# Copy photos backend +COPY apps/photos/apps/backend ./apps/photos/apps/backend + +# Install dependencies +RUN pnpm install --frozen-lockfile + +# Build shared packages first (in dependency order) +WORKDIR /app/packages/shared-errors +RUN pnpm build + +WORKDIR /app/packages/shared-nestjs-auth +RUN pnpm build + +WORKDIR /app/packages/shared-nestjs-health +RUN pnpm build + +WORKDIR /app/packages/shared-nestjs-metrics +RUN pnpm build + +WORKDIR /app/packages/shared-nestjs-setup +RUN pnpm build + +WORKDIR /app/packages/mana-core-nestjs-integration +RUN pnpm build + +# Build the backend +WORKDIR /app/apps/photos/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/photos ./apps/photos + +# Copy entrypoint script +COPY apps/photos/apps/backend/docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +WORKDIR /app/apps/photos/apps/backend + +# Expose port +EXPOSE 3039 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:3039/api/v1/health || exit 1 + +# Run entrypoint script +ENTRYPOINT ["docker-entrypoint.sh"] +CMD ["node", "dist/main.js"] diff --git a/apps/photos/apps/backend/docker-entrypoint.sh b/apps/photos/apps/backend/docker-entrypoint.sh new file mode 100644 index 000000000..180680236 --- /dev/null +++ b/apps/photos/apps/backend/docker-entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e + +echo "📋 Running database migrations..." +npx drizzle-kit push --config drizzle.config.ts --force || echo "⚠️ Migration failed, continuing anyway..." + +# Start the application +echo "🚀 Starting Photos Backend..." +exec "$@" diff --git a/apps/photos/apps/web/Dockerfile b/apps/photos/apps/web/Dockerfile new file mode 100644 index 000000000..8d500b1e0 --- /dev/null +++ b/apps/photos/apps/web/Dockerfile @@ -0,0 +1,101 @@ +# Build stage +FROM node:20-alpine AS builder + +# Build arguments for SvelteKit static env vars +ARG PUBLIC_BACKEND_URL=http://photos-backend:3039 +ARG PUBLIC_MANA_CORE_AUTH_URL=http://mana-core-auth:3001 +ARG PUBLIC_MANA_MEDIA_URL=http://mana-media:3015 + +# Set as environment variables for build +ENV PUBLIC_BACKEND_URL=$PUBLIC_BACKEND_URL +ENV PUBLIC_MANA_CORE_AUTH_URL=$PUBLIC_MANA_CORE_AUTH_URL +ENV PUBLIC_MANA_MEDIA_URL=$PUBLIC_MANA_MEDIA_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 photos 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-help-content ./packages/shared-help-content +COPY packages/shared-help-types ./packages/shared-help-types +COPY packages/shared-help-ui ./packages/shared-help-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 packages/shared-tags ./packages/shared-tags +COPY packages/shared-splitscreen ./packages/shared-splitscreen +COPY packages/shared-vite-config ./packages/shared-vite-config +COPY packages/shared-api-client ./packages/shared-api-client +COPY packages/shared-stores ./packages/shared-stores + +# Copy photos shared package +COPY apps/photos/packages/shared ./apps/photos/packages/shared + +# Copy photos web +COPY apps/photos/apps/web ./apps/photos/apps/web + +# Install dependencies +RUN pnpm install --frozen-lockfile + +# Build shared packages that need building +WORKDIR /app/packages/shared-vite-config +RUN pnpm build + +WORKDIR /app/packages/shared-auth +RUN pnpm build || true + +# Build the web app +WORKDIR /app/apps/photos/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/photos/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/photos/apps/web/node_modules ./node_modules + +# Copy built application +COPY --from=builder /app/apps/photos/apps/web/build ./build +COPY --from=builder /app/apps/photos/apps/web/package.json ./ + +# Expose port +EXPOSE 5019 + +# Set environment variables +ENV NODE_ENV=production +ENV PORT=5019 +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:5019/health || exit 1 + +# Run the app +CMD ["node", "build"] diff --git a/apps/photos/apps/web/src/routes/health/+server.ts b/apps/photos/apps/web/src/routes/health/+server.ts new file mode 100644 index 000000000..ad136563b --- /dev/null +++ b/apps/photos/apps/web/src/routes/health/+server.ts @@ -0,0 +1,10 @@ +import { json } from '@sveltejs/kit'; +import type { RequestHandler } from './$types'; + +export const GET: RequestHandler = async () => { + return json({ + status: 'ok', + service: 'photos-web', + timestamp: new Date().toISOString(), + }); +}; diff --git a/docker-compose.macmini.yml b/docker-compose.macmini.yml index 40c58b8c8..9345ce57a 100644 --- a/docker-compose.macmini.yml +++ b/docker-compose.macmini.yml @@ -105,7 +105,7 @@ services: SMTP_USER: ${SMTP_USER:-94cde5002@smtp-brevo.com} SMTP_PASSWORD: ${SMTP_PASSWORD} SMTP_FROM: Mana - 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,https://skilltree.mana.how,https://matrix.mana.how,https://element.mana.how,https://link.mana.how,https://playground.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,https://skilltree.mana.how,https://photos.mana.how,https://matrix.mana.how,https://element.mana.how,https://link.mana.how,https://playground.mana.how DUCKDB_PATH: /data/analytics/metrics.duckdb SYNAPSE_OIDC_CLIENT_SECRET: ${SYNAPSE_OIDC_CLIENT_SECRET:-} volumes: @@ -234,7 +234,7 @@ services: S3_PUBLIC_URL: https://media.mana.how MATRIX_HOMESERVER_URL: https://matrix.mana.how PUBLIC_URL: https://media.mana.how/api/v1 - CORS_ORIGINS: https://mana.how,https://nutriphi.mana.how,https://contacts.mana.how,https://chat.mana.how,https://storage.mana.how + CORS_ORIGINS: https://mana.how,https://nutriphi.mana.how,https://contacts.mana.how,https://chat.mana.how,https://storage.mana.how,https://photos.mana.how ports: - "3015:3015" healthcheck: @@ -485,6 +485,37 @@ services: retries: 3 start_period: 40s + photos-backend: + build: + context: . + dockerfile: apps/photos/apps/backend/Dockerfile + image: photos-backend:local + container_name: mana-app-photos-backend + restart: always + depends_on: + mana-auth: + condition: service_healthy + mana-media: + condition: service_healthy + environment: + NODE_ENV: production + PORT: 3039 + DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/photos + DB_HOST: postgres + DB_PORT: 5432 + DB_USER: postgres + MANA_CORE_AUTH_URL: http://mana-auth:3001 + MANA_MEDIA_URL: http://mana-media:3015 + CORS_ORIGINS: https://photos.mana.how,https://mana.how + ports: + - "3039:3039" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3039/api/v1/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + # ============================================ # Tier 4: Matrix Stack (Ports 4000-4099) # ============================================ @@ -1107,6 +1138,38 @@ services: retries: 3 start_period: 40s + photos-web: + build: + context: . + dockerfile: apps/photos/apps/web/Dockerfile + args: + PUBLIC_BACKEND_URL: http://photos-backend:3039 + PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001 + PUBLIC_MANA_MEDIA_URL: http://mana-media:3015 + image: photos-web:local + container_name: mana-app-photos-web + restart: always + depends_on: + photos-backend: + condition: service_healthy + environment: + NODE_ENV: production + PORT: 5019 + PUBLIC_BACKEND_URL: http://photos-backend:3039 + PUBLIC_MANA_CORE_AUTH_URL: http://mana-auth:3001 + PUBLIC_MANA_MEDIA_URL: http://mana-media:3015 + PUBLIC_BACKEND_URL_CLIENT: https://photos-api.mana.how + PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.mana.how + PUBLIC_MANA_MEDIA_URL_CLIENT: https://media.mana.how + ports: + - "5019:5019" + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5019/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + mana-llm: build: context: ./services/mana-llm