diff --git a/.gitignore b/.gitignore index 674f21b..e933078 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ lerna-debug.log* # misc .DS_Store notes.mdx + +# We dont need generated Prisma files +prisma/generated/ diff --git a/apps/client/.env.example b/apps/client/.env.example new file mode 100644 index 0000000..f88f1e9 --- /dev/null +++ b/apps/client/.env.example @@ -0,0 +1,8 @@ +# API Configuration +# NOTE: These are build-time variables for Vite +# They are baked into the static files during build +# To change them, rebuild the Docker image with --build-arg + +VITE_API_URL=http://localhost:9999 +VITE_APP_URL=http://localhost:80 +VITE_BETTER_AUTH_URL=http://localhost:9999/api/auth diff --git a/apps/client/Dockerfile b/apps/client/Dockerfile new file mode 100644 index 0000000..088f639 --- /dev/null +++ b/apps/client/Dockerfile @@ -0,0 +1,57 @@ +# TanStack Start (SSR) Client Dockerfile +# Multi-stage build for optimized production image +# +# NOTE: This Dockerfile expects to be run from the monorepo root +# Build command: docker build -f apps/client/Dockerfile . + +FROM oven/bun:latest AS base +WORKDIR /usr/src/app + +# Install OpenSSL (required for some dependencies) +RUN apt-get update -y && apt-get install -y openssl && rm -rf /var/lib/apt/lists/* + +# ============================================ +# Build Stage +# ============================================ +FROM base AS builder +WORKDIR /usr/src/app + +# Copy root workspace files +COPY package.json bun.lock* ./ + +# Copy the entire monorepo structure (client needs server types) +COPY apps/server ./apps/server/ +COPY apps/client ./apps/client/ + +# Install all dependencies from monorepo root +RUN bun install --frozen-lockfile + +# Set build-time environment variables (can be overridden during build) +ARG VITE_API_URL +ARG VITE_APP_URL +ARG VITE_BETTER_AUTH_URL + +ENV VITE_API_URL=${VITE_API_URL} +ENV VITE_APP_URL=${VITE_APP_URL} +ENV VITE_BETTER_AUTH_URL=${VITE_BETTER_AUTH_URL} + +# Build the client application +WORKDIR /usr/src/app/apps/client +RUN bun run build + +# ============================================ +# Production Stage - Nginx +# ============================================ +FROM nginx:alpine AS runner + +# Copy built static files to nginx html directory +COPY --from=builder /usr/src/app/apps/client/dist/client /usr/share/nginx/html + +# Copy custom nginx configuration +COPY apps/client/nginx.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + +# Start nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/client/nginx.conf b/apps/client/nginx.conf new file mode 100644 index 0000000..a46dc03 --- /dev/null +++ b/apps/client/nginx.conf @@ -0,0 +1,35 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Enable gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json; + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # SPA fallback - send all requests to index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Health check endpoint + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } +} diff --git a/bun.lock b/bun.lock index 628ec3d..ccf009a 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "learn-platform-monorepo", diff --git a/package.json b/package.json index ca89ed7..fa3bb5f 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "packages/*" ], "scripts": { - "clean": "rm -rf node_modules && rm -rf apps/*/node_modules && rm -rf packages/*/node_modules" + "clean": "rm -rf node_modules && rm -rf apps/*/node_modules && rm -rf packages/*/node_modules", + "docker:build:client": "docker build -f apps/client/Dockerfile -t learn-platform-client ." } -} +} \ No newline at end of file