Fix Forntend build issues
This commit is contained in:
@@ -1,85 +1,21 @@
|
|||||||
# Kubernetes-optimized Dockerfile for Frontend
|
# Frontend Dockerfile for Kubernetes
|
||||||
# Multi-stage build for production deployment
|
# Simple two-stage build: node for build, nginx for serve
|
||||||
|
|
||||||
# Stage 1: Build the application
|
# Stage 1: Build
|
||||||
FROM node:18-alpine AS builder
|
FROM node:18-alpine AS builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package files
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
# Install all dependencies for building
|
|
||||||
RUN npm ci --verbose && \
|
|
||||||
npm cache clean --force
|
|
||||||
|
|
||||||
# Copy source code (excluding unnecessary files like node_modules, dist, etc.)
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Create a default runtime config in the public directory if it doesn't exist to satisfy the reference in index.html
|
|
||||||
RUN if [ ! -f public/runtime-config.js ]; then \
|
|
||||||
mkdir -p public && \
|
|
||||||
echo "window.__RUNTIME_CONFIG__ = {};" > public/runtime-config.js; \
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set build-time environment variables to prevent hanging on undefined variables
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
ENV CI=true
|
|
||||||
ENV VITE_API_URL=/api
|
ENV VITE_API_URL=/api
|
||||||
ENV VITE_APP_TITLE="BakeWise"
|
ENV VITE_APP_TITLE="BakeWise"
|
||||||
ENV VITE_APP_VERSION="1.0.0"
|
ENV VITE_APP_VERSION="1.0.0"
|
||||||
ENV VITE_PILOT_MODE_ENABLED="false"
|
|
||||||
ENV VITE_PILOT_COUPON_CODE="PILOT2025"
|
|
||||||
ENV VITE_PILOT_TRIAL_MONTHS="3"
|
|
||||||
ENV VITE_STRIPE_PUBLISHABLE_KEY="pk_test_"
|
|
||||||
# Set Node.js memory limit for the build process
|
|
||||||
ENV NODE_OPTIONS="--max-old-space-size=4096"
|
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Stage 2: Production server with Nginx
|
# Stage 2: Serve with nginx
|
||||||
FROM nginx:1.25-alpine AS production
|
FROM nginx:1.25-alpine
|
||||||
|
|
||||||
# Install curl for health checks
|
|
||||||
RUN apk add --no-cache curl
|
|
||||||
|
|
||||||
# Copy main nginx configuration that sets the PID file location
|
|
||||||
COPY nginx-main.conf /etc/nginx/nginx.conf
|
|
||||||
|
|
||||||
# Remove default nginx configuration
|
|
||||||
RUN rm /etc/nginx/conf.d/default.conf
|
RUN rm /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
# Copy custom nginx configuration
|
|
||||||
COPY nginx.conf /etc/nginx/conf.d/
|
COPY nginx.conf /etc/nginx/conf.d/
|
||||||
|
|
||||||
# Copy built application from builder stage
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
# Copy and setup environment substitution script
|
|
||||||
COPY substitute-env.sh /docker-entrypoint.d/30-substitute-env.sh
|
|
||||||
|
|
||||||
# Make the script executable
|
|
||||||
RUN chmod +x /docker-entrypoint.d/30-substitute-env.sh
|
|
||||||
|
|
||||||
# Set proper permissions
|
|
||||||
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
|
||||||
chown -R nginx:nginx /var/cache/nginx && \
|
|
||||||
chown -R nginx:nginx /var/log/nginx && \
|
|
||||||
chown -R nginx:nginx /etc/nginx/conf.d
|
|
||||||
|
|
||||||
# Create nginx PID directory and fix permissions
|
|
||||||
RUN mkdir -p /var/run/nginx /var/lib/nginx/tmp && \
|
|
||||||
chown -R nginx:nginx /var/run/nginx /var/lib/nginx /etc/nginx
|
|
||||||
|
|
||||||
# Switch to non-root user
|
|
||||||
USER nginx
|
|
||||||
|
|
||||||
# Expose port 3000 (to match current setup)
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
# Health check
|
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
|
||||||
CMD curl -f http://localhost:3000/health || exit 1
|
|
||||||
|
|
||||||
# Start nginx
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,6 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700&display=swap" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700&display=swap" rel="stylesheet" />
|
||||||
|
|
||||||
<!-- Runtime configuration - MUST load before app code (Kubernetes deployment) -->
|
|
||||||
<script src="/runtime-config.js"></script>
|
|
||||||
|
|
||||||
<title>BakeWise - Gestión Inteligente para Panaderías</title>
|
<title>BakeWise - Gestión Inteligente para Panaderías</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
pid /var/run/nginx/nginx.pid;
|
|
||||||
worker_processes auto;
|
|
||||||
|
|
||||||
events {
|
|
||||||
worker_connections 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
|
||||||
}
|
|
||||||
@@ -1,92 +1,16 @@
|
|||||||
/**
|
/**
|
||||||
* Pilot Program Configuration
|
* Pilot Program Configuration
|
||||||
*
|
* Uses build-time environment variables
|
||||||
* Centralized configuration for pilot mode features.
|
|
||||||
*
|
|
||||||
* Works in two modes:
|
|
||||||
* 1. Kubernetes/Docker: Reads from window.__RUNTIME_CONFIG__ (injected at container startup)
|
|
||||||
* 2. Local Development: Reads from import.meta.env (build-time variables from .env)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
export const PILOT_CONFIG = {
|
||||||
* Helper function to get environment variable value
|
enabled: import.meta.env.VITE_PILOT_MODE_ENABLED === 'true',
|
||||||
* Tries runtime config first (Kubernetes), falls back to build-time (local dev)
|
couponCode: import.meta.env.VITE_PILOT_COUPON_CODE || 'PILOT2025',
|
||||||
*/
|
trialMonths: parseInt(import.meta.env.VITE_PILOT_TRIAL_MONTHS || '3'),
|
||||||
const getEnvVar = (key: string): string | undefined => {
|
get trialDays(): number {
|
||||||
// Try runtime config first (Kubernetes/Docker environment)
|
return this.trialMonths * 30;
|
||||||
if (typeof window !== 'undefined' && (window as any).__RUNTIME_CONFIG__) {
|
},
|
||||||
const value = (window as any).__RUNTIME_CONFIG__[key];
|
lifetimeDiscount: 20,
|
||||||
if (value !== undefined) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback to build-time environment variables (local development)
|
|
||||||
return import.meta.env[key];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Create pilot config with getter functions to ensure we always read fresh values
|
|
||||||
* This is important because runtime-config.js might load after this module
|
|
||||||
*/
|
|
||||||
const createPilotConfig = () => {
|
|
||||||
return {
|
|
||||||
/**
|
|
||||||
* Master switch for pilot mode
|
|
||||||
* When false, all pilot features are disabled globally
|
|
||||||
*/
|
|
||||||
get enabled(): boolean {
|
|
||||||
const value = getEnvVar('VITE_PILOT_MODE_ENABLED');
|
|
||||||
return value === 'true';
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Coupon code for pilot participants
|
|
||||||
*/
|
|
||||||
get couponCode(): string {
|
|
||||||
return getEnvVar('VITE_PILOT_COUPON_CODE') || 'PILOT2025';
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trial period in months for pilot participants
|
|
||||||
*/
|
|
||||||
get trialMonths(): number {
|
|
||||||
return parseInt(getEnvVar('VITE_PILOT_TRIAL_MONTHS') || '3');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trial period in days (calculated from months)
|
|
||||||
*/
|
|
||||||
get trialDays(): number {
|
|
||||||
return this.trialMonths * 30;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifetime discount percentage for pilot participants
|
|
||||||
*/
|
|
||||||
lifetimeDiscount: 20,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PILOT_CONFIG = createPilotConfig();
|
|
||||||
|
|
||||||
// Debug logging
|
|
||||||
console.log('🔧 Pilot Config Loading:', {
|
|
||||||
source: typeof window !== 'undefined' && (window as any).__RUNTIME_CONFIG__ ? 'runtime' : 'build-time',
|
|
||||||
raw: getEnvVar('VITE_PILOT_MODE_ENABLED'),
|
|
||||||
type: typeof getEnvVar('VITE_PILOT_MODE_ENABLED'),
|
|
||||||
enabled: PILOT_CONFIG.enabled,
|
|
||||||
runtimeConfigExists: typeof window !== 'undefined' && !!(window as any).__RUNTIME_CONFIG__,
|
|
||||||
runtimeConfigKeys: typeof window !== 'undefined' && (window as any).__RUNTIME_CONFIG__
|
|
||||||
? Object.keys((window as any).__RUNTIME_CONFIG__)
|
|
||||||
: []
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('✅ Pilot Config:', {
|
|
||||||
enabled: PILOT_CONFIG.enabled,
|
|
||||||
couponCode: PILOT_CONFIG.couponCode,
|
|
||||||
trialMonths: PILOT_CONFIG.trialMonths,
|
|
||||||
trialDays: PILOT_CONFIG.trialDays
|
|
||||||
});
|
|
||||||
|
|
||||||
export default PILOT_CONFIG;
|
export default PILOT_CONFIG;
|
||||||
|
|||||||
@@ -1,83 +1,33 @@
|
|||||||
// Runtime configuration for Kubernetes deployments
|
// Configuration - uses build-time environment variables
|
||||||
// This allows environment variables to be injected at container startup
|
export const config = {
|
||||||
|
VITE_API_URL: import.meta.env.VITE_API_URL || '/api',
|
||||||
|
VITE_APP_TITLE: import.meta.env.VITE_APP_TITLE || 'BakeWise',
|
||||||
|
VITE_APP_VERSION: import.meta.env.VITE_APP_VERSION || '1.0.0',
|
||||||
|
VITE_OTEL_ENABLED: import.meta.env.VITE_OTEL_ENABLED || 'true',
|
||||||
|
VITE_OTEL_TRACES_ENDPOINT: import.meta.env.VITE_OTEL_TRACES_ENDPOINT || '/api/v1/telemetry/v1/traces',
|
||||||
|
VITE_OTEL_METRICS_ENDPOINT: import.meta.env.VITE_OTEL_METRICS_ENDPOINT || '/api/v1/telemetry/v1/metrics',
|
||||||
|
};
|
||||||
|
|
||||||
interface RuntimeConfig {
|
|
||||||
VITE_API_URL: string;
|
|
||||||
VITE_APP_TITLE: string;
|
|
||||||
VITE_APP_VERSION: string;
|
|
||||||
VITE_OTEL_TRACES_ENDPOINT?: string;
|
|
||||||
VITE_OTEL_METRICS_ENDPOINT?: string;
|
|
||||||
VITE_OTEL_ENABLED?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
__RUNTIME_CONFIG__?: RuntimeConfig;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Types are defined in vite-env.d.ts
|
|
||||||
|
|
||||||
// Get configuration from runtime or fall back to build-time environment variables
|
|
||||||
function getRuntimeConfig(): RuntimeConfig {
|
|
||||||
// First try to get from window (injected at runtime in Kubernetes)
|
|
||||||
if (typeof window !== 'undefined' && window.__RUNTIME_CONFIG__) {
|
|
||||||
return window.__RUNTIME_CONFIG__;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to build-time environment variables (development/local)
|
|
||||||
return {
|
|
||||||
VITE_API_URL: import.meta.env.VITE_API_URL || 'http://localhost:8000',
|
|
||||||
VITE_APP_TITLE: import.meta.env.VITE_APP_TITLE || 'PanIA Dashboard',
|
|
||||||
VITE_APP_VERSION: import.meta.env.VITE_APP_VERSION || '1.0.0',
|
|
||||||
VITE_OTEL_TRACES_ENDPOINT: import.meta.env.VITE_OTEL_TRACES_ENDPOINT || '/api/v1/telemetry/v1/traces',
|
|
||||||
VITE_OTEL_METRICS_ENDPOINT: import.meta.env.VITE_OTEL_METRICS_ENDPOINT || '/api/v1/telemetry/v1/metrics',
|
|
||||||
VITE_OTEL_ENABLED: import.meta.env.VITE_OTEL_ENABLED || 'true',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const config = getRuntimeConfig();
|
|
||||||
|
|
||||||
// Helper function to get the API base URL
|
|
||||||
export function getApiUrl(): string {
|
export function getApiUrl(): string {
|
||||||
return config.VITE_API_URL;
|
return config.VITE_API_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get app title
|
|
||||||
export function getAppTitle(): string {
|
export function getAppTitle(): string {
|
||||||
return config.VITE_APP_TITLE;
|
return config.VITE_APP_TITLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get app version
|
|
||||||
export function getAppVersion(): string {
|
export function getAppVersion(): string {
|
||||||
return config.VITE_APP_VERSION;
|
return config.VITE_APP_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to check if running in Kubernetes
|
|
||||||
export function isKubernetesEnvironment(): boolean {
|
|
||||||
return typeof window !== 'undefined' && !!window.__RUNTIME_CONFIG__;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper to check if OpenTelemetry is enabled
|
|
||||||
export function isOpenTelemetryEnabled(): boolean {
|
export function isOpenTelemetryEnabled(): boolean {
|
||||||
return config.VITE_OTEL_ENABLED?.toLowerCase() !== 'false';
|
return config.VITE_OTEL_ENABLED?.toLowerCase() !== 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to get OpenTelemetry traces endpoint
|
|
||||||
export function getOtelTracesEndpoint(): string {
|
export function getOtelTracesEndpoint(): string {
|
||||||
return config.VITE_OTEL_TRACES_ENDPOINT || '/api/v1/telemetry/v1/traces';
|
return config.VITE_OTEL_TRACES_ENDPOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper to get OpenTelemetry metrics endpoint
|
|
||||||
export function getOtelMetricsEndpoint(): string {
|
export function getOtelMetricsEndpoint(): string {
|
||||||
return config.VITE_OTEL_METRICS_ENDPOINT || '/api/v1/telemetry/v1/metrics';
|
return config.VITE_OTEL_METRICS_ENDPOINT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug function to log current configuration
|
|
||||||
export function logConfig(): void {
|
|
||||||
console.log('Current configuration:', {
|
|
||||||
...config,
|
|
||||||
isKubernetes: isKubernetesEnvironment(),
|
|
||||||
source: isKubernetesEnvironment() ? 'runtime' : 'build-time'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
20
frontend/src/vite-env.d.ts
vendored
20
frontend/src/vite-env.d.ts
vendored
@@ -2,30 +2,16 @@
|
|||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_API_URL: string
|
readonly VITE_API_URL: string
|
||||||
readonly VITE_API_BASE_URL: string
|
|
||||||
readonly VITE_APP_TITLE: string
|
readonly VITE_APP_TITLE: string
|
||||||
readonly VITE_APP_VERSION: string
|
readonly VITE_APP_VERSION: string
|
||||||
readonly VITE_ENVIRONMENT: string
|
readonly VITE_OTEL_ENABLED?: string
|
||||||
|
readonly VITE_OTEL_TRACES_ENDPOINT?: string
|
||||||
|
readonly VITE_OTEL_METRICS_ENDPOINT?: string
|
||||||
readonly VITE_PILOT_MODE_ENABLED?: string
|
readonly VITE_PILOT_MODE_ENABLED?: string
|
||||||
readonly VITE_PILOT_COUPON_CODE?: string
|
readonly VITE_PILOT_COUPON_CODE?: string
|
||||||
readonly VITE_PILOT_TRIAL_MONTHS?: string
|
readonly VITE_PILOT_TRIAL_MONTHS?: string
|
||||||
readonly VITE_STRIPE_PUBLISHABLE_KEY?: string
|
|
||||||
// more env variables...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
readonly env: ImportMetaEnv
|
readonly env: ImportMetaEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runtime configuration injected by Kubernetes at container startup
|
|
||||||
interface Window {
|
|
||||||
__RUNTIME_CONFIG__?: {
|
|
||||||
VITE_API_URL?: string;
|
|
||||||
VITE_APP_TITLE?: string;
|
|
||||||
VITE_APP_VERSION?: string;
|
|
||||||
VITE_PILOT_MODE_ENABLED?: string;
|
|
||||||
VITE_PILOT_COUPON_CODE?: string;
|
|
||||||
VITE_PILOT_TRIAL_MONTHS?: string;
|
|
||||||
VITE_STRIPE_PUBLISHABLE_KEY?: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Handle VITE_API_URL specially to preserve empty values
|
|
||||||
# If VITE_API_URL is unset, use default; if empty, preserve empty; otherwise use value
|
|
||||||
if [ -z "${VITE_API_URL+x}" ]; then
|
|
||||||
export VITE_API_URL="/api"
|
|
||||||
elif [ -z "$VITE_API_URL" ]; then
|
|
||||||
# If VITE_API_URL is explicitly set to empty string, use relative API path
|
|
||||||
export VITE_API_URL="/api"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Default values for environment variables
|
|
||||||
export VITE_APP_TITLE=${VITE_APP_TITLE:-"BakeWise"}
|
|
||||||
export VITE_APP_VERSION=${VITE_APP_VERSION:-"1.0.0"}
|
|
||||||
|
|
||||||
# Default values for pilot program configuration
|
|
||||||
export VITE_PILOT_MODE_ENABLED=${VITE_PILOT_MODE_ENABLED:-"false"}
|
|
||||||
export VITE_PILOT_COUPON_CODE=${VITE_PILOT_COUPON_CODE:-"PILOT2025"}
|
|
||||||
export VITE_PILOT_TRIAL_MONTHS=${VITE_PILOT_TRIAL_MONTHS:-"3"}
|
|
||||||
export VITE_STRIPE_PUBLISHABLE_KEY=${VITE_STRIPE_PUBLISHABLE_KEY:-"pk_test_"}
|
|
||||||
|
|
||||||
# Create a runtime configuration file that can be loaded by the frontend
|
|
||||||
cat > /usr/share/nginx/html/runtime-config.js << EOL
|
|
||||||
window.__RUNTIME_CONFIG__ = {
|
|
||||||
VITE_API_URL: '${VITE_API_URL}',
|
|
||||||
VITE_APP_TITLE: '${VITE_APP_TITLE}',
|
|
||||||
VITE_APP_VERSION: '${VITE_APP_VERSION}',
|
|
||||||
VITE_PILOT_MODE_ENABLED: '${VITE_PILOT_MODE_ENABLED}',
|
|
||||||
VITE_PILOT_COUPON_CODE: '${VITE_PILOT_COUPON_CODE}',
|
|
||||||
VITE_PILOT_TRIAL_MONTHS: '${VITE_PILOT_TRIAL_MONTHS}',
|
|
||||||
VITE_STRIPE_PUBLISHABLE_KEY: '${VITE_STRIPE_PUBLISHABLE_KEY}'
|
|
||||||
};
|
|
||||||
EOL
|
|
||||||
|
|
||||||
echo "Runtime configuration created:"
|
|
||||||
echo " API URL: ${VITE_API_URL}"
|
|
||||||
echo " Pilot Mode: ${VITE_PILOT_MODE_ENABLED}"
|
|
||||||
echo " Pilot Coupon: ${VITE_PILOT_COUPON_CODE}"
|
|
||||||
echo " Trial Months: ${VITE_PILOT_TRIAL_MONTHS}"
|
|
||||||
Reference in New Issue
Block a user