diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ab5f8d8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,47 @@ +# Nuxt build artifacts +.output +.nuxt +dist + +# Node modules +node_modules + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment files +.env +.env.local +.env.*.local + +# IDE +.vscode +.idea +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Git +.git +.gitignore + +# Docker +Dockerfile +.dockerignore +docker-compose.yml + +# Testing +coverage +.nyc_output + +# Misc +*.md +!README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..76e27e9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,43 @@ +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies with clean cache +RUN npm ci --prefer-offline --no-audit + +# Copy source code +COPY . . + +# Build the application +RUN npm run build + +# Production stage +FROM node:20-alpine + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install only production dependencies with clean cache +RUN npm ci --prefer-offline --no-audit --omit=dev + +# Copy built application from builder stage +COPY --from=builder /app/.output ./.output + +# Expose port +EXPOSE 3000 + +# Set environment to production +ENV NODE_ENV=production + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ + CMD node -e "require('http').get('http://localhost:3000/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + +# Start the application +CMD ["node", ".output/server/index.mjs"] diff --git a/app/pages/index.vue b/app/pages/index.vue index d11b512..09137c7 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -77,9 +77,9 @@ const uploadDesignAsset = async ( throw new Error("Asset uploads can only run in the browser context."); } - const storageUrl = config.public.storageUrl; - if (!storageUrl) { - throw new Error("Storage URL is not configured."); + const backendUrl = config.public.backendUrl; + if (!backendUrl) { + throw new Error("Backend URL is not configured."); } const formData = new FormData(); @@ -92,7 +92,7 @@ const uploadDesignAsset = async ( } return await $fetch("/storage/upload", { - baseURL: storageUrl, + baseURL: backendUrl, method: "POST", headers: { "content-type": "multipart/form-data", diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0508e3f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,34 @@ +services: + slipmatz-web: + build: + context: . + dockerfile: Dockerfile + container_name: slipmatz-web + ports: + - "3000:3000" + environment: + - NODE_ENV=production + # Add your environment variables here + - NUXT_PUBLIC_FIREBASE_API_KEY=${NUXT_PUBLIC_FIREBASE_API_KEY} + - NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN=${NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN} + - NUXT_PUBLIC_FIREBASE_PROJECT_ID=${NUXT_PUBLIC_FIREBASE_PROJECT_ID} + - NUXT_PUBLIC_FIREBASE_STORAGE_BUCKET=${NUXT_PUBLIC_FIREBASE_STORAGE_BUCKET} + - NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=${NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID} + - NUXT_PUBLIC_FIREBASE_APP_ID=${NUXT_PUBLIC_FIREBASE_APP_ID} + - NUXT_PUBLIC_STORAGE_URL=${NUXT_PUBLIC_STORAGE_URL} + - NUXT_PUBLIC_BACKEND_URL=${NUXT_PUBLIC_BACKEND_URL} + - NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY} + - STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY} + restart: unless-stopped + networks: + - slipmatz-network + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +networks: + slipmatz-network: + driver: bridge