Add base kubernetes support 2
This commit is contained in:
@@ -1,38 +0,0 @@
|
|||||||
# frontend/Dockerfile.development - FIXED VERSION
|
|
||||||
FROM node:18-alpine
|
|
||||||
|
|
||||||
# Install curl for healthchecks
|
|
||||||
RUN apk add --no-cache curl
|
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Create non-root user for security but don't switch yet
|
|
||||||
RUN addgroup -g 1001 -S nodejs && \
|
|
||||||
adduser -S reactjs -u 1001 -G nodejs
|
|
||||||
|
|
||||||
# Copy package files first (better caching)
|
|
||||||
COPY package*.json ./
|
|
||||||
|
|
||||||
# Install all dependencies (including dev dependencies) as root
|
|
||||||
RUN npm ci --verbose && \
|
|
||||||
npm cache clean --force
|
|
||||||
|
|
||||||
# Copy source code
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Change ownership of all files to the non-root user
|
|
||||||
RUN chown -R reactjs:nodejs /app
|
|
||||||
|
|
||||||
# Now switch to non-root user
|
|
||||||
USER reactjs
|
|
||||||
|
|
||||||
# Expose port 3000 (Vite default)
|
|
||||||
EXPOSE 3000
|
|
||||||
|
|
||||||
# Add healthcheck
|
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
|
||||||
CMD curl -f http://localhost:3000/ || exit 1
|
|
||||||
|
|
||||||
# Start development server with host binding
|
|
||||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Production Dockerfile for Frontend with Nginx
|
# Kubernetes-optimized Dockerfile for Frontend
|
||||||
# Multi-stage build for optimal size and performance
|
# Multi-stage build for production deployment
|
||||||
|
|
||||||
# Stage 1: Build the application
|
# Stage 1: Build the application
|
||||||
FROM node:18-alpine AS builder
|
FROM node:18-alpine AS builder
|
||||||
@@ -17,6 +17,7 @@ RUN npm ci --verbose && \
|
|||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Build the application for production
|
# Build the application for production
|
||||||
|
# This will use environment variables available at build time
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Stage 2: Production server with Nginx
|
# Stage 2: Production server with Nginx
|
||||||
@@ -34,7 +35,30 @@ COPY nginx.conf /etc/nginx/conf.d/
|
|||||||
# Copy built application from builder stage
|
# Copy built application from builder stage
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
# Nginx user already exists in the base image, just ensure proper ownership
|
# Create a script to substitute environment variables at runtime
|
||||||
|
COPY <<'EOF' /docker-entrypoint.d/30-substitute-env.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Default values for environment variables
|
||||||
|
export VITE_API_URL=${VITE_API_URL:-"http://gateway-service:8000"}
|
||||||
|
export VITE_APP_TITLE=${VITE_APP_TITLE:-"PanIA Dashboard"}
|
||||||
|
export VITE_APP_VERSION=${VITE_APP_VERSION:-"1.0.0"}
|
||||||
|
|
||||||
|
# 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}'
|
||||||
|
};
|
||||||
|
EOL
|
||||||
|
|
||||||
|
echo "Runtime configuration created with API URL: ${VITE_API_URL}"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
RUN chmod +x /docker-entrypoint.d/30-substitute-env.sh
|
||||||
|
|
||||||
# Set proper permissions
|
# Set proper permissions
|
||||||
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
RUN chown -R nginx:nginx /usr/share/nginx/html && \
|
||||||
@@ -65,7 +89,7 @@ EXPOSE 3000
|
|||||||
|
|
||||||
# Health check
|
# Health check
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||||
CMD curl -f http://localhost:3000/ || exit 1
|
CMD curl -f http://localhost:3000/health || exit 1
|
||||||
|
|
||||||
# Start nginx
|
# Start nginx
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# frontend/Dockerfile.production
|
|
||||||
# Multi-stage build for production
|
|
||||||
|
|
||||||
# Build stage
|
|
||||||
FROM node:18-alpine as builder
|
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
# Copy package files
|
|
||||||
COPY package*.json ./
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN npm ci --only=production
|
|
||||||
|
|
||||||
# Copy source code
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build the application
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Production stage
|
|
||||||
FROM nginx:alpine
|
|
||||||
|
|
||||||
# Install curl for healthchecks
|
|
||||||
RUN apk add --no-cache curl
|
|
||||||
|
|
||||||
# Copy built app from builder stage
|
|
||||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
|
||||||
|
|
||||||
# Copy nginx configuration
|
|
||||||
COPY nginx.conf /etc/nginx/nginx.conf
|
|
||||||
|
|
||||||
# Expose port 80
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
# Add healthcheck
|
|
||||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
|
||||||
CMD curl -f http://localhost/ || exit 1
|
|
||||||
|
|
||||||
# Start nginx
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
@@ -22,6 +22,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
<!-- Runtime configuration - loaded by Kubernetes deployment -->
|
||||||
|
<script src="/runtime-config.js"></script>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -12,7 +12,7 @@ server {
|
|||||||
add_header X-Content-Type-Options "nosniff" always;
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com https://js.stripe.com; script-src-elem 'self' 'unsafe-inline' https://js.stripe.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' http://localhost:8000 http://localhost:8006 ws: wss:; frame-src https://js.stripe.com;" always;
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com https://js.stripe.com; script-src-elem 'self' 'unsafe-inline' https://js.stripe.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' http://gateway-service:8000 http://localhost:8000 http://localhost:8006 ws: wss:; frame-src https://js.stripe.com;" always;
|
||||||
|
|
||||||
# Gzip compression
|
# Gzip compression
|
||||||
gzip on;
|
gzip on;
|
||||||
@@ -31,9 +31,9 @@ server {
|
|||||||
application/atom+xml
|
application/atom+xml
|
||||||
image/svg+xml;
|
image/svg+xml;
|
||||||
|
|
||||||
# API proxy to gateway service (Kubernetes internal name)
|
# API proxy to gateway service (Kubernetes service name)
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://gateway:8000;
|
proxy_pass http://gateway-service:8000;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection 'upgrade';
|
proxy_set_header Connection 'upgrade';
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
* React Query doesn't replace HTTP clients - it manages data fetching/caching/sync
|
* React Query doesn't replace HTTP clients - it manages data fetching/caching/sync
|
||||||
*/
|
*/
|
||||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
|
||||||
|
import { getApiUrl } from '../../config/runtime';
|
||||||
|
|
||||||
export interface ApiError {
|
export interface ApiError {
|
||||||
message: string;
|
message: string;
|
||||||
@@ -55,7 +56,7 @@ class ApiClient {
|
|||||||
config: AxiosRequestConfig;
|
config: AxiosRequestConfig;
|
||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
constructor(baseURL: string = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8000/api/v1') {
|
constructor(baseURL: string = getApiUrl() + '/api/v1') {
|
||||||
this.baseURL = baseURL;
|
this.baseURL = baseURL;
|
||||||
|
|
||||||
this.client = axios.create({
|
this.client = axios.create({
|
||||||
|
|||||||
62
frontend/src/config/runtime.ts
Normal file
62
frontend/src/config/runtime.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
// Runtime configuration for Kubernetes deployments
|
||||||
|
// This allows environment variables to be injected at container startup
|
||||||
|
|
||||||
|
interface RuntimeConfig {
|
||||||
|
VITE_API_URL: string;
|
||||||
|
VITE_APP_TITLE: string;
|
||||||
|
VITE_APP_VERSION: 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',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = getRuntimeConfig();
|
||||||
|
|
||||||
|
// Helper function to get the API base URL
|
||||||
|
export function getApiUrl(): string {
|
||||||
|
return config.VITE_API_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get app title
|
||||||
|
export function getAppTitle(): string {
|
||||||
|
return config.VITE_APP_TITLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to get app version
|
||||||
|
export function getAppVersion(): string {
|
||||||
|
return config.VITE_APP_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to check if running in Kubernetes
|
||||||
|
export function isKubernetesEnvironment(): boolean {
|
||||||
|
return typeof window !== 'undefined' && !!window.__RUNTIME_CONFIG__;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug function to log current configuration
|
||||||
|
export function logConfig(): void {
|
||||||
|
console.log('Current configuration:', {
|
||||||
|
...config,
|
||||||
|
isKubernetes: isKubernetesEnvironment(),
|
||||||
|
source: isKubernetesEnvironment() ? 'runtime' : 'build-time'
|
||||||
|
});
|
||||||
|
}
|
||||||
14
frontend/src/vite-env.d.ts
vendored
Normal file
14
frontend/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_API_URL: string
|
||||||
|
readonly VITE_API_BASE_URL: string
|
||||||
|
readonly VITE_APP_TITLE: string
|
||||||
|
readonly VITE_APP_VERSION: string
|
||||||
|
readonly VITE_ENVIRONMENT: string
|
||||||
|
// more env variables...
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv
|
||||||
|
}
|
||||||
@@ -28,10 +28,12 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: process.env.NODE_ENV === 'development'
|
target: process.env.VITE_API_URL ||
|
||||||
? 'http://gateway:8000' // Use internal service name in Kubernetes
|
(process.env.NODE_ENV === 'development' && process.env.KUBERNETES_SERVICE_HOST
|
||||||
: 'http://localhost:8000',
|
? 'http://gateway-service:8000' // Kubernetes internal service
|
||||||
|
: 'http://localhost:8000'), // Local development
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/api/, ''),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -98,6 +98,11 @@ spec:
|
|||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: rabbitmq-secrets
|
name: rabbitmq-secrets
|
||||||
key: RABBITMQ_PASSWORD
|
key: RABBITMQ_PASSWORD
|
||||||
|
- name: RABBITMQ_VHOST
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: bakery-config
|
||||||
|
key: RABBITMQ_VHOST
|
||||||
- name: NOTIFICATION_SERVICE_URL
|
- name: NOTIFICATION_SERVICE_URL
|
||||||
valueFrom:
|
valueFrom:
|
||||||
configMapKeyRef:
|
configMapKeyRef:
|
||||||
@@ -22,18 +22,33 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: frontend
|
- name: frontend
|
||||||
image: bakery/dashboard:latest
|
image: bakery/dashboard:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 3000
|
- containerPort: 3000
|
||||||
name: http
|
name: http
|
||||||
env:
|
env:
|
||||||
- name: NODE_ENV
|
- name: NODE_ENV
|
||||||
value: "development"
|
value: "production"
|
||||||
- name: VITE_APP_TITLE
|
- name: VITE_APP_TITLE
|
||||||
value: "PanIA Dashboard"
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: bakery-config
|
||||||
|
key: VITE_APP_TITLE
|
||||||
- name: VITE_APP_VERSION
|
- name: VITE_APP_VERSION
|
||||||
value: "1.0.0"
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: bakery-config
|
||||||
|
key: VITE_APP_VERSION
|
||||||
- name: VITE_API_URL
|
- name: VITE_API_URL
|
||||||
value: "http://gateway-service:8000"
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: bakery-config
|
||||||
|
key: VITE_API_URL
|
||||||
|
- name: VITE_ENVIRONMENT
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: bakery-config
|
||||||
|
key: VITE_ENVIRONMENT
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: "512Mi"
|
memory: "512Mi"
|
||||||
@@ -7,16 +7,24 @@ metadata:
|
|||||||
app.kubernetes.io/name: bakery-ia
|
app.kubernetes.io/name: bakery-ia
|
||||||
app.kubernetes.io/component: config
|
app.kubernetes.io/component: config
|
||||||
data:
|
data:
|
||||||
# Environment Settings
|
# ================================================================
|
||||||
ENVIRONMENT: "development"
|
# ENVIRONMENT & BUILD SETTINGS
|
||||||
DEBUG: "true"
|
# ================================================================
|
||||||
|
ENVIRONMENT: "production"
|
||||||
|
DEBUG: "false"
|
||||||
LOG_LEVEL: "INFO"
|
LOG_LEVEL: "INFO"
|
||||||
AUTO_RELOAD: "true"
|
BUILD_DATE: "2024-01-20T10:00:00Z"
|
||||||
|
VCS_REF: "latest"
|
||||||
|
IMAGE_TAG: "latest"
|
||||||
|
DOMAIN: "localhost"
|
||||||
|
AUTO_RELOAD: "false"
|
||||||
PROFILING_ENABLED: "false"
|
PROFILING_ENABLED: "false"
|
||||||
MOCK_EXTERNAL_APIS: "false"
|
MOCK_EXTERNAL_APIS: "false"
|
||||||
TESTING: "false"
|
TESTING: "false"
|
||||||
|
|
||||||
# Service Discovery
|
# ================================================================
|
||||||
|
# SERVICE DISCOVERY (KUBERNETES INTERNAL)
|
||||||
|
# ================================================================
|
||||||
REDIS_HOST: "redis-service"
|
REDIS_HOST: "redis-service"
|
||||||
REDIS_PORT: "6379"
|
REDIS_PORT: "6379"
|
||||||
RABBITMQ_HOST: "rabbitmq-service"
|
RABBITMQ_HOST: "rabbitmq-service"
|
||||||
@@ -24,7 +32,7 @@ data:
|
|||||||
RABBITMQ_MANAGEMENT_PORT: "15672"
|
RABBITMQ_MANAGEMENT_PORT: "15672"
|
||||||
RABBITMQ_VHOST: "/"
|
RABBITMQ_VHOST: "/"
|
||||||
|
|
||||||
# Database Hosts
|
# Database Hosts (Kubernetes Services)
|
||||||
AUTH_DB_HOST: "auth-db-service"
|
AUTH_DB_HOST: "auth-db-service"
|
||||||
TENANT_DB_HOST: "tenant-db-service"
|
TENANT_DB_HOST: "tenant-db-service"
|
||||||
TRAINING_DB_HOST: "training-db-service"
|
TRAINING_DB_HOST: "training-db-service"
|
||||||
@@ -40,10 +48,8 @@ data:
|
|||||||
PRODUCTION_DB_HOST: "production-db-service"
|
PRODUCTION_DB_HOST: "production-db-service"
|
||||||
ALERT_PROCESSOR_DB_HOST: "alert-processor-db-service"
|
ALERT_PROCESSOR_DB_HOST: "alert-processor-db-service"
|
||||||
|
|
||||||
# Database Ports
|
# Database Configuration
|
||||||
DB_PORT: "5432"
|
DB_PORT: "5432"
|
||||||
|
|
||||||
# Database Names
|
|
||||||
AUTH_DB_NAME: "auth_db"
|
AUTH_DB_NAME: "auth_db"
|
||||||
TENANT_DB_NAME: "tenant_db"
|
TENANT_DB_NAME: "tenant_db"
|
||||||
TRAINING_DB_NAME: "training_db"
|
TRAINING_DB_NAME: "training_db"
|
||||||
@@ -58,11 +64,12 @@ data:
|
|||||||
ORDERS_DB_NAME: "orders_db"
|
ORDERS_DB_NAME: "orders_db"
|
||||||
PRODUCTION_DB_NAME: "production_db"
|
PRODUCTION_DB_NAME: "production_db"
|
||||||
ALERT_PROCESSOR_DB_NAME: "alert_processor_db"
|
ALERT_PROCESSOR_DB_NAME: "alert_processor_db"
|
||||||
|
POSTGRES_INITDB_ARGS: "--encoding=UTF-8 --lc-collate=C --lc-ctype=C"
|
||||||
|
|
||||||
# PostgreSQL Settings
|
# ================================================================
|
||||||
POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256"
|
# SERVICE URLS (KUBERNETES INTERNAL)
|
||||||
|
# ================================================================
|
||||||
# Service URLs (internal cluster communication)
|
GATEWAY_URL: "http://gateway-service:8000"
|
||||||
AUTH_SERVICE_URL: "http://auth-service:8000"
|
AUTH_SERVICE_URL: "http://auth-service:8000"
|
||||||
TENANT_SERVICE_URL: "http://tenant-service:8000"
|
TENANT_SERVICE_URL: "http://tenant-service:8000"
|
||||||
TRAINING_SERVICE_URL: "http://training-service:8000"
|
TRAINING_SERVICE_URL: "http://training-service:8000"
|
||||||
@@ -77,9 +84,242 @@ data:
|
|||||||
ORDERS_SERVICE_URL: "http://orders-service:8000"
|
ORDERS_SERVICE_URL: "http://orders-service:8000"
|
||||||
PRODUCTION_SERVICE_URL: "http://production-service:8000"
|
PRODUCTION_SERVICE_URL: "http://production-service:8000"
|
||||||
|
|
||||||
# Cache Settings
|
# ================================================================
|
||||||
REDIS_MAX_MEMORY: "512mb"
|
# AUTHENTICATION & SECURITY SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
JWT_ALGORITHM: "HS256"
|
||||||
|
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: "30"
|
||||||
|
JWT_REFRESH_TOKEN_EXPIRE_DAYS: "7"
|
||||||
|
ENABLE_SERVICE_AUTH: "false"
|
||||||
|
PASSWORD_MIN_LENGTH: "8"
|
||||||
|
PASSWORD_REQUIRE_UPPERCASE: "true"
|
||||||
|
PASSWORD_REQUIRE_LOWERCASE: "true"
|
||||||
|
PASSWORD_REQUIRE_NUMBERS: "true"
|
||||||
|
PASSWORD_REQUIRE_SYMBOLS: "false"
|
||||||
|
BCRYPT_ROUNDS: "12"
|
||||||
|
MAX_LOGIN_ATTEMPTS: "5"
|
||||||
|
LOCKOUT_DURATION_MINUTES: "30"
|
||||||
|
|
||||||
# Monitoring
|
# ================================================================
|
||||||
|
# CORS & API CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
CORS_ORIGINS: "http://frontend-service:3000,http://localhost:3000,https://bakery.yourdomain.com"
|
||||||
|
CORS_ALLOW_CREDENTIALS: "true"
|
||||||
|
RATE_LIMIT_ENABLED: "true"
|
||||||
|
RATE_LIMIT_REQUESTS: "100"
|
||||||
|
RATE_LIMIT_WINDOW: "60"
|
||||||
|
RATE_LIMIT_BURST: "10"
|
||||||
|
API_DOCS_ENABLED: "true"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# HTTP CLIENT SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
HTTP_TIMEOUT: "30000"
|
||||||
|
HTTP_RETRIES: "3"
|
||||||
|
HTTP_RETRY_DELAY: "1.0"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# EXTERNAL API CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
AEMET_BASE_URL: "https://opendata.aemet.es/opendata"
|
||||||
|
AEMET_TIMEOUT: "60"
|
||||||
|
AEMET_RETRY_ATTEMPTS: "3"
|
||||||
|
MADRID_OPENDATA_BASE_URL: "https://datos.madrid.es"
|
||||||
|
MADRID_OPENDATA_TIMEOUT: "30"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# PAYMENT CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
STRIPE_PUBLISHABLE_KEY: "pk_test_your_stripe_publishable_key_here"
|
||||||
|
SQUARE_APPLICATION_ID: "your-square-application-id"
|
||||||
|
SQUARE_ENVIRONMENT: "sandbox"
|
||||||
|
TOAST_ENVIRONMENT: "sandbox"
|
||||||
|
LIGHTSPEED_ENVIRONMENT: "sandbox"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# EMAIL CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
SMTP_HOST: "smtp.gmail.com"
|
||||||
|
SMTP_PORT: "587"
|
||||||
|
SMTP_TLS: "true"
|
||||||
|
SMTP_SSL: "false"
|
||||||
|
DEFAULT_FROM_EMAIL: "noreply@bakeryforecast.es"
|
||||||
|
DEFAULT_FROM_NAME: "Bakery-Forecast"
|
||||||
|
EMAIL_FROM_ADDRESS: "alerts@bakery.local"
|
||||||
|
EMAIL_FROM_NAME: "Bakery Alert System"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# WHATSAPP CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
WHATSAPP_BASE_URL: "https://api.twilio.com"
|
||||||
|
WHATSAPP_FROM_NUMBER: "whatsapp:+14155238886"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# ALERT SYSTEM CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
ALERT_PROCESSOR_INSTANCES: "2"
|
||||||
|
ALERT_PROCESSOR_MAX_MEMORY: "512M"
|
||||||
|
ALERT_BATCH_SIZE: "10"
|
||||||
|
ALERT_PROCESSING_TIMEOUT: "30"
|
||||||
|
EMAIL_ENABLED: "true"
|
||||||
|
WHATSAPP_ENABLED: "true"
|
||||||
|
SSE_ENABLED: "true"
|
||||||
|
PUSH_NOTIFICATIONS_ENABLED: "false"
|
||||||
|
ALERT_DEDUPLICATION_WINDOW_MINUTES: "15"
|
||||||
|
RECOMMENDATION_DEDUPLICATION_WINDOW_MINUTES: "60"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# CHECK FREQUENCIES (CRON EXPRESSIONS)
|
||||||
|
# ================================================================
|
||||||
|
STOCK_CHECK_FREQUENCY: "*/5"
|
||||||
|
EXPIRY_CHECK_FREQUENCY: "*/2"
|
||||||
|
TEMPERATURE_CHECK_FREQUENCY: "*/2"
|
||||||
|
PRODUCTION_DELAY_CHECK_FREQUENCY: "*/5"
|
||||||
|
CAPACITY_CHECK_FREQUENCY: "*/10"
|
||||||
|
INVENTORY_OPTIMIZATION_FREQUENCY: "*/30"
|
||||||
|
EFFICIENCY_RECOMMENDATIONS_FREQUENCY: "*/30"
|
||||||
|
ENERGY_RECOMMENDATIONS_FREQUENCY: "0"
|
||||||
|
WASTE_REDUCTION_FREQUENCY: "0"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# MODEL STORAGE & TRAINING
|
||||||
|
# ================================================================
|
||||||
|
MODEL_STORAGE_PATH: "/app/models"
|
||||||
|
MODEL_BACKUP_ENABLED: "true"
|
||||||
|
MODEL_VERSIONING_ENABLED: "true"
|
||||||
|
MAX_TRAINING_TIME_MINUTES: "30"
|
||||||
|
MAX_CONCURRENT_TRAINING_JOBS: "3"
|
||||||
|
MIN_TRAINING_DATA_DAYS: "30"
|
||||||
|
TRAINING_BATCH_SIZE: "1000"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# OPTIMIZATION SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
ENABLE_HYPERPARAMETER_OPTIMIZATION: "true"
|
||||||
|
ENABLE_PRODUCT_SPECIFIC_PARAMS: "true"
|
||||||
|
ENABLE_DYNAMIC_PARAM_SELECTION: "true"
|
||||||
|
OPTUNA_N_TRIALS: "50"
|
||||||
|
OPTUNA_CV_FOLDS: "3"
|
||||||
|
OPTUNA_TIMEOUT_MINUTES: "10"
|
||||||
|
HIGH_VOLUME_THRESHOLD: "1.0"
|
||||||
|
INTERMITTENT_THRESHOLD: "0.6"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# PROPHET PARAMETERS
|
||||||
|
# ================================================================
|
||||||
|
PROPHET_SEASONALITY_MODE: "additive"
|
||||||
|
PROPHET_CHANGEPOINT_PRIOR_SCALE: "0.05"
|
||||||
|
PROPHET_SEASONALITY_PRIOR_SCALE: "10.0"
|
||||||
|
PROPHET_HOLIDAYS_PRIOR_SCALE: "10.0"
|
||||||
|
PROPHET_DAILY_SEASONALITY: "true"
|
||||||
|
PROPHET_WEEKLY_SEASONALITY: "true"
|
||||||
|
PROPHET_YEARLY_SEASONALITY: "true"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# BUSINESS CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
SERVICE_VERSION: "1.0.0"
|
||||||
|
TIMEZONE: "Europe/Madrid"
|
||||||
|
LOCALE: "es_ES.UTF-8"
|
||||||
|
CURRENCY: "EUR"
|
||||||
|
BUSINESS_HOUR_START: "7"
|
||||||
|
BUSINESS_HOUR_END: "20"
|
||||||
|
ENABLE_SPANISH_HOLIDAYS: "true"
|
||||||
|
ENABLE_MADRID_HOLIDAYS: "true"
|
||||||
|
SCHOOL_CALENDAR_ENABLED: "true"
|
||||||
|
WEATHER_IMPACT_ENABLED: "true"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# MONITORING & LOGGING
|
||||||
|
# ================================================================
|
||||||
|
LOG_FORMAT: "json"
|
||||||
|
LOG_FILE_ENABLED: "false"
|
||||||
|
LOG_FILE_PATH: "/app/logs"
|
||||||
|
LOG_ROTATION_SIZE: "100MB"
|
||||||
|
LOG_RETENTION_DAYS: "30"
|
||||||
|
PROMETHEUS_ENABLED: "true"
|
||||||
PROMETHEUS_RETENTION: "200h"
|
PROMETHEUS_RETENTION: "200h"
|
||||||
TIMEZONE: "UTC"
|
HEALTH_CHECK_TIMEOUT: "30"
|
||||||
|
HEALTH_CHECK_INTERVAL: "30"
|
||||||
|
PROMETHEUS_RETENTION_DAYS: "30"
|
||||||
|
GRAFANA_ROOT_URL: "http://monitoring.bakery-ia.local/grafana"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# DATA COLLECTION SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
WEATHER_COLLECTION_INTERVAL_HOURS: "1"
|
||||||
|
TRAFFIC_COLLECTION_INTERVAL_HOURS: "1"
|
||||||
|
EVENTS_COLLECTION_INTERVAL_HOURS: "6"
|
||||||
|
DATA_VALIDATION_ENABLED: "true"
|
||||||
|
OUTLIER_DETECTION_ENABLED: "true"
|
||||||
|
DATA_COMPLETENESS_THRESHOLD: "0.8"
|
||||||
|
DEFAULT_LATITUDE: "40.4168"
|
||||||
|
DEFAULT_LONGITUDE: "-3.7038"
|
||||||
|
LOCATION_RADIUS_KM: "50.0"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# NOTIFICATION SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
ENABLE_EMAIL_NOTIFICATIONS: "true"
|
||||||
|
ENABLE_WHATSAPP_NOTIFICATIONS: "true"
|
||||||
|
ENABLE_PUSH_NOTIFICATIONS: "false"
|
||||||
|
MAX_RETRY_ATTEMPTS: "3"
|
||||||
|
RETRY_DELAY_SECONDS: "60"
|
||||||
|
NOTIFICATION_BATCH_SIZE: "100"
|
||||||
|
EMAIL_RATE_LIMIT_PER_HOUR: "1000"
|
||||||
|
WHATSAPP_RATE_LIMIT_PER_HOUR: "100"
|
||||||
|
DEFAULT_LANGUAGE: "es"
|
||||||
|
DATE_FORMAT: "%d/%m/%Y"
|
||||||
|
TIME_FORMAT: "%H:%M"
|
||||||
|
EMAIL_TEMPLATES_PATH: "/app/templates/email"
|
||||||
|
WHATSAPP_TEMPLATES_PATH: "/app/templates/whatsapp"
|
||||||
|
IMMEDIATE_DELIVERY: "true"
|
||||||
|
SCHEDULED_DELIVERY_ENABLED: "true"
|
||||||
|
DELIVERY_TRACKING_ENABLED: "true"
|
||||||
|
OPEN_TRACKING_ENABLED: "true"
|
||||||
|
CLICK_TRACKING_ENABLED: "true"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# FORECASTING SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
MAX_FORECAST_DAYS: "30"
|
||||||
|
MIN_HISTORICAL_DAYS: "60"
|
||||||
|
PREDICTION_CONFIDENCE_THRESHOLD: "0.8"
|
||||||
|
PREDICTION_CACHE_TTL_HOURS: "6"
|
||||||
|
FORECAST_BATCH_SIZE: "100"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# BUSINESS RULES
|
||||||
|
# ================================================================
|
||||||
|
WEEKEND_ADJUSTMENT_FACTOR: "0.8"
|
||||||
|
HOLIDAY_ADJUSTMENT_FACTOR: "0.5"
|
||||||
|
TEMPERATURE_THRESHOLD_COLD: "10.0"
|
||||||
|
TEMPERATURE_THRESHOLD_HOT: "30.0"
|
||||||
|
RAIN_IMPACT_FACTOR: "0.7"
|
||||||
|
HIGH_DEMAND_THRESHOLD: "1.5"
|
||||||
|
LOW_DEMAND_THRESHOLD: "0.5"
|
||||||
|
STOCKOUT_RISK_THRESHOLD: "0.9"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# CACHE SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
REDIS_MAX_MEMORY: "512mb"
|
||||||
|
REDIS_MAX_CONNECTIONS: "50"
|
||||||
|
REDIS_DB: "1"
|
||||||
|
WEATHER_CACHE_TTL_HOURS: "1"
|
||||||
|
TRAFFIC_CACHE_TTL_HOURS: "1"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# FRONTEND CONFIGURATION
|
||||||
|
# ================================================================
|
||||||
|
VITE_APP_TITLE: "PanIA Dashboard"
|
||||||
|
VITE_APP_VERSION: "1.0.0"
|
||||||
|
VITE_API_URL: "http://gateway-service:8000"
|
||||||
|
VITE_ENVIRONMENT: "production"
|
||||||
|
|
||||||
|
# ================================================================
|
||||||
|
# LOCATION SETTINGS
|
||||||
|
# ================================================================
|
||||||
|
NOMINATIM_PBF_URL: "http://download.geofabrik.de/europe/spain-latest.osm.pbf"
|
||||||
|
NOMINATIM_MEMORY_LIMIT: "8G"
|
||||||
|
NOMINATIM_CPU_LIMIT: "4"
|
||||||
@@ -51,9 +51,11 @@ resources:
|
|||||||
# Frontend
|
# Frontend
|
||||||
- components/frontend/frontend-service.yaml
|
- components/frontend/frontend-service.yaml
|
||||||
|
|
||||||
commonLabels:
|
labels:
|
||||||
app.kubernetes.io/part-of: bakery-ia
|
- includeSelectors: true
|
||||||
app.kubernetes.io/managed-by: kustomize
|
pairs:
|
||||||
|
app.kubernetes.io/part-of: bakery-ia
|
||||||
|
app.kubernetes.io/managed-by: kustomize
|
||||||
|
|
||||||
images:
|
images:
|
||||||
- name: bakery/auth-service
|
- name: bakery/auth-service
|
||||||
|
|||||||
@@ -8,37 +8,37 @@ metadata:
|
|||||||
app.kubernetes.io/component: database
|
app.kubernetes.io/component: database
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
# Database Users (base64 encoded)
|
# Database Users (base64 encoded from .env)
|
||||||
AUTH_DB_USER: YmFrZXJ5X2F1dGg= # bakery_auth
|
AUTH_DB_USER: YXV0aF91c2Vy # auth_user
|
||||||
TENANT_DB_USER: YmFrZXJ5X3RlbmFudA== # bakery_tenant
|
TENANT_DB_USER: dGVuYW50X3VzZXI= # tenant_user
|
||||||
TRAINING_DB_USER: YmFrZXJ5X3RyYWluaW5n # bakery_training
|
TRAINING_DB_USER: dHJhaW5pbmdfdXNlcg== # training_user
|
||||||
FORECASTING_DB_USER: YmFrZXJ5X2ZvcmVjYXN0aW5n # bakery_forecasting
|
FORECASTING_DB_USER: Zm9yZWNhc3RpbmdfdXNlcg== # forecasting_user
|
||||||
SALES_DB_USER: YmFrZXJ5X3NhbGVz # bakery_sales
|
SALES_DB_USER: c2FsZXNfdXNlcg== # sales_user
|
||||||
EXTERNAL_DB_USER: YmFrZXJ5X2V4dGVybmFs # bakery_external
|
EXTERNAL_DB_USER: ZXh0ZXJuYWxfdXNlcg== # external_user
|
||||||
NOTIFICATION_DB_USER: YmFrZXJ5X25vdGlmaWNhdGlvbg== # bakery_notification
|
NOTIFICATION_DB_USER: bm90aWZpY2F0aW9uX3VzZXI= # notification_user
|
||||||
INVENTORY_DB_USER: YmFrZXJ5X2ludmVudG9yeQ== # bakery_inventory
|
INVENTORY_DB_USER: aW52ZW50b3J5X3VzZXI= # inventory_user
|
||||||
RECIPES_DB_USER: YmFrZXJ5X3JlY2lwZXM= # bakery_recipes
|
RECIPES_DB_USER: cmVjaXBlc191c2Vy # recipes_user
|
||||||
SUPPLIERS_DB_USER: YmFrZXJ5X3N1cHBsaWVycw== # bakery_suppliers
|
SUPPLIERS_DB_USER: c3VwcGxpZXJzX3VzZXI= # suppliers_user
|
||||||
POS_DB_USER: YmFrZXJ5X3Bvcw== # bakery_pos
|
POS_DB_USER: cG9zX3VzZXI= # pos_user
|
||||||
ORDERS_DB_USER: YmFrZXJ5X29yZGVycw== # bakery_orders
|
ORDERS_DB_USER: b3JkZXJzX3VzZXI= # orders_user
|
||||||
PRODUCTION_DB_USER: YmFrZXJ5X3Byb2R1Y3Rpb24= # bakery_production
|
PRODUCTION_DB_USER: cHJvZHVjdGlvbl91c2Vy # production_user
|
||||||
ALERT_PROCESSOR_DB_USER: YmFrZXJ5X2FsZXJ0X3Byb2Nlc3Nvcg== # bakery_alert_processor
|
ALERT_PROCESSOR_DB_USER: YWxlcnRfcHJvY2Vzc29yX3VzZXI= # alert_processor_user
|
||||||
|
|
||||||
# Database Passwords (base64 encoded - change these in production!)
|
# Database Passwords (base64 encoded from .env)
|
||||||
AUTH_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
AUTH_DB_PASSWORD: YXV0aF9wYXNzMTIz # auth_pass123
|
||||||
TENANT_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
TENANT_DB_PASSWORD: dGVuYW50X3Bhc3MxMjM= # tenant_pass123
|
||||||
TRAINING_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
TRAINING_DB_PASSWORD: dHJhaW5pbmdfcGFzczEyMw== # training_pass123
|
||||||
FORECASTING_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
FORECASTING_DB_PASSWORD: Zm9yZWNhc3RpbmdfcGFzczEyMw== # forecasting_pass123
|
||||||
SALES_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
SALES_DB_PASSWORD: c2FsZXNfcGFzczEyMw== # sales_pass123
|
||||||
EXTERNAL_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
EXTERNAL_DB_PASSWORD: ZXh0ZXJuYWxfcGFzczEyMw== # external_pass123
|
||||||
NOTIFICATION_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
NOTIFICATION_DB_PASSWORD: bm90aWZpY2F0aW9uX3Bhc3MxMjM= # notification_pass123
|
||||||
INVENTORY_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
INVENTORY_DB_PASSWORD: aW52ZW50b3J5X3Bhc3MxMjM= # inventory_pass123
|
||||||
RECIPES_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
RECIPES_DB_PASSWORD: cmVjaXBlc19wYXNzMTIz # recipes_pass123
|
||||||
SUPPLIERS_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
SUPPLIERS_DB_PASSWORD: c3VwcGxpZXJzX3Bhc3MxMjM= # suppliers_pass123
|
||||||
POS_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
POS_DB_PASSWORD: cG9zX3Bhc3MxMjM= # pos_pass123
|
||||||
ORDERS_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
ORDERS_DB_PASSWORD: b3JkZXJzX3Bhc3MxMjM= # orders_pass123
|
||||||
PRODUCTION_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
PRODUCTION_DB_PASSWORD: cHJvZHVjdGlvbl9wYXNzMTIz # production_pass123
|
||||||
ALERT_PROCESSOR_DB_PASSWORD: ZGV2X3Bhc3N3b3JkXzEyMw== # dev_password_123
|
ALERT_PROCESSOR_DB_PASSWORD: YWxlcnRfcHJvY2Vzc29yX3Bhc3MxMjM= # alert_processor_pass123
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -51,7 +51,7 @@ metadata:
|
|||||||
app.kubernetes.io/component: redis
|
app.kubernetes.io/component: redis
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
REDIS_PASSWORD: ZGV2X3JlZGlzXzEyMw== # dev_redis_123
|
REDIS_PASSWORD: cmVkaXNfcGFzczEyMw== # redis_pass123
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -64,8 +64,9 @@ metadata:
|
|||||||
app.kubernetes.io/component: rabbitmq
|
app.kubernetes.io/component: rabbitmq
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
RABBITMQ_USER: YmFrZXJ5X3VzZXI= # bakery_user
|
RABBITMQ_USER: YmFrZXJ5 # bakery
|
||||||
RABBITMQ_PASSWORD: ZGV2X3JhYmJpdF8xMjM= # dev_rabbit_123
|
RABBITMQ_PASSWORD: Zm9yZWNhc3QxMjM= # forecast123
|
||||||
|
RABBITMQ_ERLANG_COOKIE: YmFrZXJ5LXNlY3JldC1jb29raWU= # bakery-secret-cookie
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -78,8 +79,51 @@ metadata:
|
|||||||
app.kubernetes.io/component: auth
|
app.kubernetes.io/component: auth
|
||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
JWT_SECRET_KEY: ZGV2X2p3dF9zZWNyZXRfa2V5XzEyMzQ1Njc4OTA= # dev_jwt_secret_key_1234567890
|
JWT_SECRET_KEY: eW91ci1zdXBlci1zZWNyZXQtand0LWtleS1jaGFuZ2UtaW4tcHJvZHVjdGlvbi1taW4tMzItY2hhcmFjdGVycy1sb25n # your-super-secret-jwt-key-change-in-production-min-32-characters-long
|
||||||
JWT_REFRESH_SECRET_KEY: ZGV2X2p3dF9yZWZyZXNoX3NlY3JldF9rZXlfMTIzNDU2Nzg5MA== # dev_jwt_refresh_secret_key_1234567890
|
JWT_REFRESH_SECRET_KEY: eW91ci1zdXBlci1zZWNyZXQtcmVmcmVzaC1qd3Qta2V5LWNoYW5nZS1pbi1wcm9kdWN0aW9uLW1pbi0zMi1jaGFyYWN0ZXJzLWxvbmc= # your-super-secret-refresh-jwt-key-change-in-production-min-32-characters-long
|
||||||
|
SERVICE_API_KEY: c2VydmljZS1hcGkta2V5LWNoYW5nZS1pbi1wcm9kdWN0aW9u # service-api-key-change-in-production
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: external-api-secrets
|
||||||
|
namespace: bakery-ia
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: bakery-ia
|
||||||
|
app.kubernetes.io/component: external-apis
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
AEMET_API_KEY: ZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKemRXSWlPaUoxWVd4bVlYSnZRR2R0WVdsc0xtTnZiU0lzSW1wMGFTSTZJbVJqWldWbU5URXdMVGRtWXpFdE5HTXhOeTFoT0RaaUxXUTROemRsWkRjNVpEbGxOeUlzSW1semN5STZJa0ZGVFVWVUlpd2lhV0YwSWpveE56VXlPRE13TURnM0xDSjFjMlZ5U1dRaU9pSmtZMlZsWmpVeE1DMDNabU14TFRSak1UY3RZVGcyWkMxa09EYzNaV1EzT1dRNVpUY2lMQ0p5YjJ4bElqb2lJbjAuQzA0N2dhaUVoV2hINEl0RGdrSFN3ZzhIektUend3ODdUT1BUSTJSZ01mOGotMnc=
|
||||||
|
MADRID_OPENDATA_API_KEY: eW91ci1tYWRyaWQtb3BlbmRhdGEta2V5LWhlcmU= # your-madrid-opendata-key-here
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: payment-secrets
|
||||||
|
namespace: bakery-ia
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: bakery-ia
|
||||||
|
app.kubernetes.io/component: payments
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
STRIPE_SECRET_KEY: c2tfdGVzdF95b3VyX3N0cmlwZV9zZWNyZXRfa2V5X2hlcmU= # sk_test_your_stripe_secret_key_here
|
||||||
|
STRIPE_WEBHOOK_SECRET: d2hzZWNfeW91cl9zdHJpcGVfd2ViaG9va19zZWNyZXRfaGVyZQ== # whsec_your_stripe_webhook_secret_here
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: email-secrets
|
||||||
|
namespace: bakery-ia
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: bakery-ia
|
||||||
|
app.kubernetes.io/component: notifications
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
SMTP_USER: eW91ci1lbWFpbEBnbWFpbC5jb20= # your-email@gmail.com
|
||||||
|
SMTP_PASSWORD: eW91ci1hcHAtc3BlY2lmaWMtcGFzc3dvcmQ= # your-app-specific-password
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -93,4 +137,42 @@ metadata:
|
|||||||
type: Opaque
|
type: Opaque
|
||||||
data:
|
data:
|
||||||
GRAFANA_ADMIN_USER: YWRtaW4= # admin
|
GRAFANA_ADMIN_USER: YWRtaW4= # admin
|
||||||
GRAFANA_ADMIN_PASSWORD: ZGV2X2dyYWZhbmFfMTIz # dev_grafana_123
|
GRAFANA_ADMIN_PASSWORD: YWRtaW4xMjM= # admin123
|
||||||
|
GRAFANA_SECRET_KEY: Z3JhZmFuYS1zZWNyZXQta2V5LWNoYW5nZS1pbi1wcm9kdWN0aW9u # grafana-secret-key-change-in-production
|
||||||
|
PGADMIN_EMAIL: YWRtaW5AYmFrZXJ5LmxvY2Fs # admin@bakery.local
|
||||||
|
PGADMIN_PASSWORD: YWRtaW4xMjM= # admin123
|
||||||
|
REDIS_COMMANDER_USER: YWRtaW4= # admin
|
||||||
|
REDIS_COMMANDER_PASSWORD: YWRtaW4xMjM= # admin123
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: pos-integration-secrets
|
||||||
|
namespace: bakery-ia
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: bakery-ia
|
||||||
|
app.kubernetes.io/component: pos
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
SQUARE_ACCESS_TOKEN: eW91ci1zcXVhcmUtYWNjZXNzLXRva2Vu # your-square-access-token
|
||||||
|
SQUARE_WEBHOOK_SECRET: eW91ci1zcXVhcmUtd2ViaG9vay1zZWNyZXQ= # your-square-webhook-secret
|
||||||
|
TOAST_API_KEY: eW91ci10b2FzdC1hcGkta2V5 # your-toast-api-key
|
||||||
|
TOAST_API_SECRET: eW91ci10b2FzdC1hcGktc2VjcmV0 # your-toast-api-secret
|
||||||
|
TOAST_WEBHOOK_SECRET: eW91ci10b2FzdC13ZWJob29rLXNlY3JldA== # your-toast-webhook-secret
|
||||||
|
LIGHTSPEED_API_KEY: eW91ci1saWdodHNwZWVkLWFwaS1rZXk= # your-lightspeed-api-key
|
||||||
|
LIGHTSPEED_API_SECRET: eW91ci1saWdodHNwZWVkLWFwaS1zZWNyZXQ= # your-lightspeed-api-secret
|
||||||
|
LIGHTSPEED_WEBHOOK_SECRET: eW91ci1saWdodHNwZWVkLXdlYmhvb2stc2VjcmV0 # your-lightspeed-webhook-secret
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: whatsapp-secrets
|
||||||
|
namespace: bakery-ia
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: bakery-ia
|
||||||
|
app.kubernetes.io/component: notifications
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
WHATSAPP_API_KEY: eW91ci13aGF0c2FwcC1hcGkta2V5LWhlcmU= # your-whatsapp-api-key-here
|
||||||
@@ -5,12 +5,18 @@ metadata:
|
|||||||
namespace: bakery-ia
|
namespace: bakery-ia
|
||||||
data:
|
data:
|
||||||
# Development specific overrides
|
# Development specific overrides
|
||||||
|
ENVIRONMENT: "development"
|
||||||
DEBUG: "true"
|
DEBUG: "true"
|
||||||
LOG_LEVEL: "DEBUG"
|
LOG_LEVEL: "DEBUG"
|
||||||
AUTO_RELOAD: "true"
|
AUTO_RELOAD: "true"
|
||||||
PROFILING_ENABLED: "true"
|
PROFILING_ENABLED: "true"
|
||||||
MOCK_EXTERNAL_APIS: "true"
|
MOCK_EXTERNAL_APIS: "true"
|
||||||
|
|
||||||
|
# Frontend Development Configuration
|
||||||
|
VITE_ENVIRONMENT: "development"
|
||||||
|
VITE_API_URL: "http://gateway-service:8000"
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: networking.k8s.io/v1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
|
|||||||
@@ -12,6 +12,101 @@ resources:
|
|||||||
patchesStrategicMerge:
|
patchesStrategicMerge:
|
||||||
- dev-patches.yaml
|
- dev-patches.yaml
|
||||||
|
|
||||||
|
patchesJson6902:
|
||||||
|
- target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: auth-db
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources
|
||||||
|
value:
|
||||||
|
requests:
|
||||||
|
memory: "64Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
- target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: redis
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources
|
||||||
|
value:
|
||||||
|
requests:
|
||||||
|
memory: "64Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
- target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: rabbitmq
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources
|
||||||
|
value:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "300m"
|
||||||
|
- target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: auth-service
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources
|
||||||
|
value:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
- target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: frontend
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/imagePullPolicy
|
||||||
|
value: Never
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources
|
||||||
|
value:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
- target:
|
||||||
|
group: apps
|
||||||
|
version: v1
|
||||||
|
kind: Deployment
|
||||||
|
name: alert-processor-service
|
||||||
|
patch: |-
|
||||||
|
- op: replace
|
||||||
|
path: /spec/template/spec/containers/0/resources
|
||||||
|
value:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
|
||||||
configMapGenerator:
|
configMapGenerator:
|
||||||
- name: bakery-dev-config
|
- name: bakery-dev-config
|
||||||
literals:
|
literals:
|
||||||
@@ -26,9 +121,11 @@ secretGenerator:
|
|||||||
literals:
|
literals:
|
||||||
- DEV_MODE=true
|
- DEV_MODE=true
|
||||||
|
|
||||||
commonLabels:
|
labels:
|
||||||
environment: development
|
- includeSelectors: true
|
||||||
tier: local
|
pairs:
|
||||||
|
environment: development
|
||||||
|
tier: local
|
||||||
|
|
||||||
images:
|
images:
|
||||||
- name: bakery/auth-service
|
- name: bakery/auth-service
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import os
|
|||||||
|
|
||||||
class AuthSettings(BaseServiceSettings):
|
class AuthSettings(BaseServiceSettings):
|
||||||
"""Auth service specific settings"""
|
"""Auth service specific settings"""
|
||||||
|
|
||||||
# Service Identity
|
# Service Identity
|
||||||
APP_NAME: str = "Authentication Service"
|
APP_NAME: str = "Authentication Service"
|
||||||
SERVICE_NAME: str = "auth-service"
|
SERVICE_NAME: str = "auth-service"
|
||||||
DESCRIPTION: str = "User authentication and authorization service"
|
DESCRIPTION: str = "User authentication and authorization service"
|
||||||
|
|
||||||
# Database configuration (secure approach - build from components)
|
# Database configuration (secure approach - build from components)
|
||||||
@property
|
@property
|
||||||
def DATABASE_URL(self) -> str:
|
def DATABASE_URL(self) -> str:
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ class BaseServiceSettings(BaseSettings):
|
|||||||
# ================================================================
|
# ================================================================
|
||||||
# DATABASE CONFIGURATION
|
# DATABASE CONFIGURATION
|
||||||
# ================================================================
|
# ================================================================
|
||||||
|
|
||||||
# Primary database URL (should be overridden by each service)
|
# Note: DATABASE_URL is defined as a property in each service-specific config
|
||||||
DATABASE_URL: str = os.getenv("DATABASE_URL", "")
|
# to construct the URL from secure environment variables
|
||||||
|
|
||||||
# Database connection settings
|
# Database connection settings
|
||||||
DB_POOL_SIZE: int = int(os.getenv("DB_POOL_SIZE", "10"))
|
DB_POOL_SIZE: int = int(os.getenv("DB_POOL_SIZE", "10"))
|
||||||
@@ -75,8 +75,23 @@ class BaseServiceSettings(BaseSettings):
|
|||||||
# ================================================================
|
# ================================================================
|
||||||
# RABBITMQ CONFIGURATION
|
# RABBITMQ CONFIGURATION
|
||||||
# ================================================================
|
# ================================================================
|
||||||
|
|
||||||
RABBITMQ_URL: str = os.getenv("RABBITMQ_URL", "amqp://bakery:forecast123@rabbitmq:5672/")
|
@property
|
||||||
|
def RABBITMQ_URL(self) -> str:
|
||||||
|
"""Build RabbitMQ URL from secure components"""
|
||||||
|
# Try complete URL first (for backward compatibility)
|
||||||
|
complete_url = os.getenv("RABBITMQ_URL")
|
||||||
|
if complete_url:
|
||||||
|
return complete_url
|
||||||
|
|
||||||
|
# Build from components (secure approach)
|
||||||
|
user = os.getenv("RABBITMQ_USER", "bakery")
|
||||||
|
password = os.getenv("RABBITMQ_PASSWORD", "forecast123")
|
||||||
|
host = os.getenv("RABBITMQ_HOST", "rabbitmq-service")
|
||||||
|
port = os.getenv("RABBITMQ_PORT", "5672")
|
||||||
|
vhost = os.getenv("RABBITMQ_VHOST", "/")
|
||||||
|
|
||||||
|
return f"amqp://{user}:{password}@{host}:{port}{vhost}"
|
||||||
RABBITMQ_EXCHANGE: str = os.getenv("RABBITMQ_EXCHANGE", "bakery_events")
|
RABBITMQ_EXCHANGE: str = os.getenv("RABBITMQ_EXCHANGE", "bakery_events")
|
||||||
RABBITMQ_QUEUE_PREFIX: str = os.getenv("RABBITMQ_QUEUE_PREFIX", "bakery")
|
RABBITMQ_QUEUE_PREFIX: str = os.getenv("RABBITMQ_QUEUE_PREFIX", "bakery")
|
||||||
RABBITMQ_RETRY_ATTEMPTS: int = int(os.getenv("RABBITMQ_RETRY_ATTEMPTS", "3"))
|
RABBITMQ_RETRY_ATTEMPTS: int = int(os.getenv("RABBITMQ_RETRY_ATTEMPTS", "3"))
|
||||||
|
|||||||
Reference in New Issue
Block a user