From cf6c9e7bd7febe29694725d272caa8480233ae17 Mon Sep 17 00:00:00 2001 From: dvirlabs <114520947+dvirlabs@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:50:49 +0200 Subject: [PATCH 1/2] Update schema.sql --- aws/my-recipes-chart-aws/Chart.yaml | 14 -- .../add-missing-tables-configmap.yaml | 45 ----- .../templates/add-missing-tables-job.yaml | 49 ----- .../templates/admin-init-configmap.yaml | 99 ---------- .../templates/admin-init-job.yaml | 75 -------- .../templates/app-secrets.yaml | 35 ---- .../templates/backend-deployment.yaml | 119 ------------ .../templates/backend-service.yaml | 17 -- .../templates/db-migration-configmap.yaml | 54 ------ .../templates/db-migration-job.yaml | 69 ------- .../templates/db-schema-configmap.yaml | 134 ------------- .../templates/db-secret.yaml | 23 --- .../templates/db-service.yaml | 39 ---- .../templates/db-statefulset.yaml | 89 --------- .../templates/frontend-deployment.yaml | 57 ------ .../templates/frontend-service.yaml | 17 -- .../templates/ingress.yaml | 89 --------- aws/my-recipes-chart-aws/values.yaml | 182 ------------------ aws/values.yaml | 110 ----------- 19 files changed, 1316 deletions(-) delete mode 100644 aws/my-recipes-chart-aws/Chart.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/add-missing-tables-job.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/admin-init-configmap.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/admin-init-job.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/app-secrets.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/backend-deployment.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/backend-service.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/db-migration-configmap.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/db-migration-job.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/db-schema-configmap.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/db-secret.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/db-service.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/db-statefulset.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/frontend-deployment.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/frontend-service.yaml delete mode 100644 aws/my-recipes-chart-aws/templates/ingress.yaml delete mode 100644 aws/my-recipes-chart-aws/values.yaml delete mode 100644 aws/values.yaml diff --git a/aws/my-recipes-chart-aws/Chart.yaml b/aws/my-recipes-chart-aws/Chart.yaml deleted file mode 100644 index 86c815b..0000000 --- a/aws/my-recipes-chart-aws/Chart.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v2 -name: my-recipes -description: Complete recipe management application with PostgreSQL, FastAPI backend, and React frontend -type: application -version: 1.0.0 -appVersion: "1.0.0" -keywords: - - recipes - - fastapi - - react - - postgresql -maintainers: - - name: Development Team - diff --git a/aws/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml b/aws/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml deleted file mode 100644 index d15cad9..0000000 --- a/aws/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-add-missing-tables - namespace: {{ .Values.global.namespace }} -data: - add-tables.sql: | - -- Create grocery lists table - CREATE TABLE IF NOT EXISTS grocery_lists ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL, - items TEXT[] NOT NULL DEFAULT '{}', - owner_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - is_pinned BOOLEAN DEFAULT FALSE, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - - -- Create grocery list shares table - CREATE TABLE IF NOT EXISTS grocery_list_shares ( - id SERIAL PRIMARY KEY, - list_id INTEGER NOT NULL REFERENCES grocery_lists(id) ON DELETE CASCADE, - shared_with_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - can_edit BOOLEAN DEFAULT FALSE, - shared_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE(list_id, shared_with_user_id) - ); - - CREATE INDEX IF NOT EXISTS idx_grocery_lists_owner_id ON grocery_lists (owner_id); - CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_list_id ON grocery_list_shares (list_id); - CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_user_id ON grocery_list_shares (shared_with_user_id); - - -- Create notifications table - CREATE TABLE IF NOT EXISTS notifications ( - id SERIAL PRIMARY KEY, - user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - type TEXT NOT NULL, - message TEXT NOT NULL, - related_id INTEGER, - is_read BOOLEAN DEFAULT FALSE, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - - CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications (user_id); - CREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications (is_read); diff --git a/aws/my-recipes-chart-aws/templates/add-missing-tables-job.yaml b/aws/my-recipes-chart-aws/templates/add-missing-tables-job.yaml deleted file mode 100644 index e0ca1bc..0000000 --- a/aws/my-recipes-chart-aws/templates/add-missing-tables-job.yaml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ .Release.Name }}-add-missing-tables - namespace: {{ .Values.global.namespace }} - annotations: - "helm.sh/hook": post-upgrade - "helm.sh/hook-weight": "6" - "helm.sh/hook-delete-policy": before-hook-creation -spec: - template: - spec: - restartPolicy: Never - containers: - - name: add-tables - image: postgres:16-alpine - env: - - name: PGHOST - value: {{ .Release.Name }}-db - - name: PGPORT - value: "{{ .Values.postgres.port }}" - - name: PGDATABASE - value: {{ .Values.postgres.database }} - - name: PGUSER - value: {{ .Values.postgres.user }} - - name: PGPASSWORD - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_PASSWORD - command: - - sh - - -c - - | - echo "Waiting for database to be ready..." - until pg_isready -h $PGHOST -p $PGPORT -U $PGUSER; do - echo "Database not ready, waiting..." - sleep 2 - done - echo "Database ready, adding missing tables..." - psql -v ON_ERROR_STOP=1 -f /sql/add-tables.sql - echo "Tables added successfully!" - volumeMounts: - - name: sql - mountPath: /sql - volumes: - - name: sql - configMap: - name: {{ .Release.Name }}-add-missing-tables diff --git a/aws/my-recipes-chart-aws/templates/admin-init-configmap.yaml b/aws/my-recipes-chart-aws/templates/admin-init-configmap.yaml deleted file mode 100644 index 7bda3cd..0000000 --- a/aws/my-recipes-chart-aws/templates/admin-init-configmap.yaml +++ /dev/null @@ -1,99 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-admin-init - namespace: {{ .Values.global.namespace }} -data: - create-admin.py: | - #!/usr/bin/env python3 - import os - import sys - import psycopg2 - import bcrypt - from time import sleep - - def wait_for_db(): - """Wait for database to be ready""" - max_retries = 30 - retry_count = 0 - - while retry_count < max_retries: - try: - conn = psycopg2.connect( - host=os.environ['DB_HOST'], - port=os.environ['DB_PORT'], - database=os.environ['DB_NAME'], - user=os.environ['DB_USER'], - password=os.environ['DB_PASSWORD'] - ) - conn.close() - print("✓ Database is ready") - return True - except Exception as e: - retry_count += 1 - print(f"Waiting for database... ({retry_count}/{max_retries})") - sleep(2) - - print("✗ Database connection timeout") - return False - - def create_admin_user(): - """Create admin user if not exists""" - try: - # Hash the password - password = os.environ.get('ADMIN_PASSWORD', 'admin123') - password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') - - # Connect to database - conn = psycopg2.connect( - host=os.environ['DB_HOST'], - port=os.environ['DB_PORT'], - database=os.environ['DB_NAME'], - user=os.environ['DB_USER'], - password=os.environ['DB_PASSWORD'] - ) - cur = conn.cursor() - - # Insert admin user - cur.execute(""" - INSERT INTO users (username, email, password_hash, first_name, last_name, display_name, is_admin) - VALUES (%s, %s, %s, %s, %s, %s, %s) - ON CONFLICT (username) DO UPDATE SET - email = EXCLUDED.email, - password_hash = EXCLUDED.password_hash, - first_name = EXCLUDED.first_name, - last_name = EXCLUDED.last_name, - display_name = EXCLUDED.display_name, - is_admin = EXCLUDED.is_admin - """, ( - os.environ.get('ADMIN_USERNAME', 'admin'), - os.environ.get('ADMIN_EMAIL', 'admin@myrecipes.local'), - password_hash, - os.environ.get('ADMIN_FIRST_NAME', 'Admin'), - os.environ.get('ADMIN_LAST_NAME', 'User'), - os.environ.get('ADMIN_DISPLAY_NAME', 'מנהל'), - True - )) - - conn.commit() - cur.close() - conn.close() - - print(f"✓ Admin user '{os.environ.get('ADMIN_USERNAME', 'admin')}' created/updated successfully") - return True - - except Exception as e: - print(f"✗ Error creating admin user: {e}") - return False - - if __name__ == "__main__": - print("Starting admin user initialization...") - - if not wait_for_db(): - sys.exit(1) - - if not create_admin_user(): - sys.exit(1) - - print("✓ Admin user initialization completed") - sys.exit(0) diff --git a/aws/my-recipes-chart-aws/templates/admin-init-job.yaml b/aws/my-recipes-chart-aws/templates/admin-init-job.yaml deleted file mode 100644 index 511ec36..0000000 --- a/aws/my-recipes-chart-aws/templates/admin-init-job.yaml +++ /dev/null @@ -1,75 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ .Release.Name }}-admin-init-{{ .Release.Revision }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-admin-init - component: init - annotations: - "helm.sh/hook": post-install,post-upgrade - "helm.sh/hook-weight": "10" - "helm.sh/hook-delete-policy": before-hook-creation -spec: - ttlSecondsAfterFinished: 300 - template: - metadata: - labels: - app: {{ .Release.Name }}-admin-init - spec: - restartPolicy: Never - containers: - - name: admin-init - image: python:3.12-slim - command: - - /bin/sh - - -c - - | - pip install --no-cache-dir psycopg2-binary bcrypt > /dev/null 2>&1 - python3 /scripts/create-admin.py - env: - - name: DB_HOST - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_HOST - - name: DB_PORT - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_PORT - - name: DB_NAME - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_NAME - - name: DB_USER - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_USER - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_PASSWORD - - name: ADMIN_USERNAME - value: {{ .Values.admin.username | quote }} - - name: ADMIN_EMAIL - value: {{ .Values.admin.email | quote }} - - name: ADMIN_PASSWORD - value: {{ .Values.admin.password | quote }} - - name: ADMIN_FIRST_NAME - value: {{ .Values.admin.firstName | quote }} - - name: ADMIN_LAST_NAME - value: {{ .Values.admin.lastName | quote }} - - name: ADMIN_DISPLAY_NAME - value: {{ .Values.admin.displayName | quote }} - volumeMounts: - - name: init-script - mountPath: /scripts - volumes: - - name: init-script - configMap: - name: {{ .Release.Name }}-admin-init - defaultMode: 0755 diff --git a/aws/my-recipes-chart-aws/templates/app-secrets.yaml b/aws/my-recipes-chart-aws/templates/app-secrets.yaml deleted file mode 100644 index 93285f3..0000000 --- a/aws/my-recipes-chart-aws/templates/app-secrets.yaml +++ /dev/null @@ -1,35 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-app-secrets - namespace: {{ .Values.global.namespace }} -type: Opaque -stringData: - # Google OAuth - GOOGLE_CLIENT_ID: {{ .Values.oauth.google.clientId | quote }} - GOOGLE_CLIENT_SECRET: {{ .Values.oauth.google.clientSecret | quote }} - GOOGLE_REDIRECT_URI: {{ .Values.oauth.google.redirectUri | quote }} - - # Microsoft Entra ID (Azure AD) OAuth - AZURE_CLIENT_ID: {{ .Values.oauth.azure.clientId | quote }} - AZURE_CLIENT_SECRET: {{ .Values.oauth.azure.clientSecret | quote }} - AZURE_TENANT_ID: {{ .Values.oauth.azure.tenantId | quote }} - AZURE_REDIRECT_URI: {{ .Values.oauth.azure.redirectUri | quote }} - - # Email Configuration - SMTP_HOST: {{ .Values.email.smtpHost | quote }} - SMTP_PORT: {{ .Values.email.smtpPort | quote }} - SMTP_USER: {{ .Values.email.smtpUser | quote }} - SMTP_PASSWORD: {{ .Values.email.smtpPassword | quote }} - SMTP_FROM: {{ .Values.email.smtpFrom | quote }} - - # Frontend URL for redirects - FRONTEND_URL: {{ .Values.frontend.externalUrl | quote }} - - # S3 Backup Configuration - S3_ENDPOINT: {{ .Values.s3.endpoint | quote }} - S3_ACCESS_KEY: {{ .Values.s3.accessKey | quote }} - S3_SECRET_KEY: {{ .Values.s3.secretKey | quote }} - S3_BUCKET_NAME: {{ .Values.s3.bucketName | quote }} - S3_REGION: {{ .Values.s3.region | quote }} - BACKUP_INTERVAL: {{ .Values.s3.backupInterval | quote }} diff --git a/aws/my-recipes-chart-aws/templates/backend-deployment.yaml b/aws/my-recipes-chart-aws/templates/backend-deployment.yaml deleted file mode 100644 index b7379bd..0000000 --- a/aws/my-recipes-chart-aws/templates/backend-deployment.yaml +++ /dev/null @@ -1,119 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Release.Name }}-{{ .Values.backend.name }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-{{ .Values.backend.name }} - component: backend -spec: - replicas: {{ .Values.backend.replicaCount }} - selector: - matchLabels: - app: {{ .Release.Name }}-{{ .Values.backend.name }} - template: - metadata: - labels: - app: {{ .Release.Name }}-{{ .Values.backend.name }} - component: backend - spec: - initContainers: - - name: db-migration - image: postgres:16-alpine - command: - - /bin/sh - - -c - - | - echo "Waiting for database to be ready..." - until pg_isready -h $DB_HOST -U $DB_USER; do - echo "Database not ready, waiting..." - sleep 2 - done - echo "Database is ready, running migration..." - PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -U $DB_USER -d $DB_NAME -f /migration/migrate.sql - echo "Migration completed successfully" - env: - - name: DB_HOST - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_HOST - - name: DB_PORT - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_PORT - - name: DB_NAME - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_NAME - - name: DB_USER - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_USER - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_PASSWORD - volumeMounts: - - name: migration-script - mountPath: /migration - containers: - - name: {{ .Values.backend.name }} - image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}" - imagePullPolicy: {{ .Values.backend.image.pullPolicy }} - ports: - - containerPort: {{ .Values.backend.service.targetPort }} - name: http - protocol: TCP - env: - {{- if .Values.backend.env }} - {{- range $key, $value := .Values.backend.env }} - - name: {{ $key }} - value: {{ $value | quote }} - {{- end }} - {{- end }} - envFrom: - - secretRef: - name: {{ .Release.Name }}-db-credentials - - secretRef: - name: {{ .Release.Name }}-app-secrets - startupProbe: - httpGet: - path: /docs - port: http - initialDelaySeconds: 15 - periodSeconds: 5 - timeoutSeconds: 3 - failureThreshold: 30 - livenessProbe: - httpGet: - path: /docs - port: http - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - readinessProbe: - httpGet: - path: /docs - port: http - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 3 - failureThreshold: 2 - resources: - requests: - cpu: {{ .Values.backend.resources.requests.cpu }} - memory: {{ .Values.backend.resources.requests.memory }} - limits: - cpu: {{ .Values.backend.resources.limits.cpu }} - memory: {{ .Values.backend.resources.limits.memory }} - volumes: - - name: migration-script - configMap: - name: {{ .Release.Name }}-db-migration - diff --git a/aws/my-recipes-chart-aws/templates/backend-service.yaml b/aws/my-recipes-chart-aws/templates/backend-service.yaml deleted file mode 100644 index 6608df6..0000000 --- a/aws/my-recipes-chart-aws/templates/backend-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ .Release.Name }}-{{ .Values.backend.name }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-{{ .Values.backend.name }} - component: backend -spec: - type: {{ .Values.backend.service.type }} - ports: - - port: {{ .Values.backend.service.port }} - targetPort: {{ .Values.backend.service.targetPort }} - protocol: TCP - name: http - selector: - app: {{ .Release.Name }}-{{ .Values.backend.name }} diff --git a/aws/my-recipes-chart-aws/templates/db-migration-configmap.yaml b/aws/my-recipes-chart-aws/templates/db-migration-configmap.yaml deleted file mode 100644 index 5a7c4da..0000000 --- a/aws/my-recipes-chart-aws/templates/db-migration-configmap.yaml +++ /dev/null @@ -1,54 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-db-migration - namespace: {{ .Values.global.namespace }} -data: - migrate.sql: | - -- Add made_by column to recipes if it doesn't exist - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'recipes' AND column_name = 'made_by' - ) THEN - ALTER TABLE recipes ADD COLUMN made_by TEXT; - END IF; - END $$; - - -- Create index if it doesn't exist - CREATE INDEX IF NOT EXISTS idx_recipes_made_by ON recipes (made_by); - - -- Add is_admin column to users if it doesn't exist - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'users' AND column_name = 'is_admin' - ) THEN - ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT FALSE; - END IF; - END $$; - - -- Add auth_provider column to users if it doesn't exist - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'users' AND column_name = 'auth_provider' - ) THEN - ALTER TABLE users ADD COLUMN auth_provider TEXT DEFAULT 'local'; - END IF; - END $$; - - -- Verify recipes schema - SELECT column_name, data_type - FROM information_schema.columns - WHERE table_name = 'recipes' - ORDER BY ordinal_position; - - -- Verify users schema - SELECT column_name, data_type - FROM information_schema.columns - WHERE table_name = 'users' - ORDER BY ordinal_position; diff --git a/aws/my-recipes-chart-aws/templates/db-migration-job.yaml b/aws/my-recipes-chart-aws/templates/db-migration-job.yaml deleted file mode 100644 index f153342..0000000 --- a/aws/my-recipes-chart-aws/templates/db-migration-job.yaml +++ /dev/null @@ -1,69 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: {{ .Release.Name }}-db-migration-{{ .Release.Revision }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-db-migration - component: migration - annotations: - "helm.sh/hook": post-upgrade,post-install - "helm.sh/hook-weight": "5" - "helm.sh/hook-delete-policy": before-hook-creation -spec: - ttlSecondsAfterFinished: 300 - template: - metadata: - labels: - app: {{ .Release.Name }}-db-migration - spec: - restartPolicy: Never - containers: - - name: migrate - image: postgres:16-alpine - command: - - /bin/sh - - -c - - | - echo "Waiting for database to be ready..." - until pg_isready -h $DB_HOST -U $DB_USER; do - echo "Database not ready, waiting..." - sleep 2 - done - echo "Database is ready, running migration..." - PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -U $DB_USER -d $DB_NAME -f /migration/migrate.sql - echo "Migration completed successfully" - env: - - name: DB_HOST - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_HOST - - name: DB_PORT - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_PORT - - name: DB_NAME - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_NAME - - name: DB_USER - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_USER - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: {{ .Release.Name }}-db-credentials - key: DB_PASSWORD - volumeMounts: - - name: migration-script - mountPath: /migration - volumes: - - name: migration-script - configMap: - name: {{ .Release.Name }}-db-migration - diff --git a/aws/my-recipes-chart-aws/templates/db-schema-configmap.yaml b/aws/my-recipes-chart-aws/templates/db-schema-configmap.yaml deleted file mode 100644 index c6ee6dc..0000000 --- a/aws/my-recipes-chart-aws/templates/db-schema-configmap.yaml +++ /dev/null @@ -1,134 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-db-schema - namespace: {{ .Values.global.namespace }} -data: - schema.sql: | - -- Create users table - CREATE TABLE IF NOT EXISTS users ( - id SERIAL PRIMARY KEY, - username TEXT UNIQUE NOT NULL, - email TEXT UNIQUE NOT NULL, - password_hash TEXT NOT NULL, - first_name TEXT, - last_name TEXT, - display_name TEXT NOT NULL, - is_admin BOOLEAN DEFAULT FALSE, - auth_provider TEXT DEFAULT 'local', - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - - CREATE INDEX IF NOT EXISTS idx_users_username ON users (username); - CREATE INDEX IF NOT EXISTS idx_users_email ON users (email); - - -- Create recipes table (matching backend schema with TEXT[] arrays) - CREATE TABLE IF NOT EXISTS recipes ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL, - meal_type TEXT NOT NULL, -- breakfast / lunch / dinner / snack - time_minutes INTEGER NOT NULL, - tags TEXT[] NOT NULL DEFAULT '{}', -- {"מהיר", "בריא"} - ingredients TEXT[] NOT NULL DEFAULT '{}', -- {"ביצה", "עגבניה", "מלח"} - steps TEXT[] NOT NULL DEFAULT '{}', -- {"לחתוך", "לבשל", ...} - image TEXT, -- Base64-encoded image or image URL - made_by TEXT, -- Person who created this recipe version - user_id INTEGER REFERENCES users(id) ON DELETE SET NULL, -- Recipe owner - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - - -- Indexes for filters - CREATE INDEX IF NOT EXISTS idx_recipes_meal_type - ON recipes (meal_type); - - CREATE INDEX IF NOT EXISTS idx_recipes_time_minutes - ON recipes (time_minutes); - - CREATE INDEX IF NOT EXISTS idx_recipes_made_by - ON recipes (made_by); - - CREATE INDEX IF NOT EXISTS idx_recipes_user_id - ON recipes (user_id); - - -- Add new columns to existing users table - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'users' AND column_name = 'first_name' - ) THEN - ALTER TABLE users ADD COLUMN first_name TEXT; - END IF; - END $$; - - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'users' AND column_name = 'last_name' - ) THEN - ALTER TABLE users ADD COLUMN last_name TEXT; - END IF; - END $$; - - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'users' AND column_name = 'display_name' - ) THEN - ALTER TABLE users ADD COLUMN display_name TEXT; - -- Set display_name to username for existing users - UPDATE users SET display_name = username WHERE display_name IS NULL; - ALTER TABLE users ALTER COLUMN display_name SET NOT NULL; - END IF; - END $$; - - DO $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 FROM information_schema.columns - WHERE table_name = 'users' AND column_name = 'is_admin' - ) THEN - ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT FALSE; - END IF; - END $$; - - -- Create grocery lists table - CREATE TABLE IF NOT EXISTS grocery_lists ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL, - items TEXT[] NOT NULL DEFAULT '{}', - owner_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - is_pinned BOOLEAN DEFAULT FALSE, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - - -- Create grocery list shares table - CREATE TABLE IF NOT EXISTS grocery_list_shares ( - id SERIAL PRIMARY KEY, - list_id INTEGER NOT NULL REFERENCES grocery_lists(id) ON DELETE CASCADE, - shared_with_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - can_edit BOOLEAN DEFAULT FALSE, - shared_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - UNIQUE(list_id, shared_with_user_id) - ); - - CREATE INDEX IF NOT EXISTS idx_grocery_lists_owner_id ON grocery_lists (owner_id); - CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_list_id ON grocery_list_shares (list_id); - CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_user_id ON grocery_list_shares (shared_with_user_id); - - -- Create notifications table - CREATE TABLE IF NOT EXISTS notifications ( - id SERIAL PRIMARY KEY, - user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, - type TEXT NOT NULL, - message TEXT NOT NULL, - related_id INTEGER, - is_read BOOLEAN DEFAULT FALSE, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP - ); - - CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications (user_id); - CREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications (is_read); diff --git a/aws/my-recipes-chart-aws/templates/db-secret.yaml b/aws/my-recipes-chart-aws/templates/db-secret.yaml deleted file mode 100644 index aef2e21..0000000 --- a/aws/my-recipes-chart-aws/templates/db-secret.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-db-credentials - namespace: {{ .Values.global.namespace }} -type: Opaque -stringData: - {{- if .Values.database }} - # External database (e.g., AWS RDS) - DB_HOST: {{ .Values.database.host | quote }} - DB_PORT: {{ .Values.database.port | quote }} - DB_NAME: {{ .Values.database.name | quote }} - DB_USER: {{ .Values.database.user | quote }} - DB_PASSWORD: {{ .Values.database.password | quote }} - {{- else }} - # In-cluster PostgreSQL - DB_HOST: {{ printf "%s-%s-headless.%s.svc.cluster.local" .Release.Name .Values.postgres.name .Values.global.namespace }} - DB_PORT: "{{ .Values.postgres.port }}" - DB_NAME: {{ .Values.postgres.database | quote }} - DB_USER: {{ .Values.postgres.user | quote }} - DB_PASSWORD: {{ .Values.postgres.password | quote }} - {{- end }} - diff --git a/aws/my-recipes-chart-aws/templates/db-service.yaml b/aws/my-recipes-chart-aws/templates/db-service.yaml deleted file mode 100644 index c4704d3..0000000 --- a/aws/my-recipes-chart-aws/templates/db-service.yaml +++ /dev/null @@ -1,39 +0,0 @@ -{{- if not .Values.database }} -{{- /* Only deploy in-cluster PostgreSQL services if external database is not configured */ -}} -apiVersion: v1 -kind: Service -metadata: - name: {{ .Release.Name }}-{{ .Values.postgres.name }}-headless - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-{{ .Values.postgres.name }} - component: database -spec: - clusterIP: None - selector: - app: {{ .Release.Name }}-{{ .Values.postgres.name }} - ports: - - name: postgres - port: {{ .Values.postgres.port }} - targetPort: {{ .Values.postgres.port }} - protocol: TCP ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ .Release.Name }}-{{ .Values.postgres.name }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-{{ .Values.postgres.name }} - component: database -spec: - type: {{ .Values.postgres.service.type }} - selector: - app: {{ .Release.Name }}-{{ .Values.postgres.name }} - ports: - - name: postgres - port: {{ .Values.postgres.service.port }} - targetPort: {{ .Values.postgres.port }} - protocol: TCP -{{- end }} - diff --git a/aws/my-recipes-chart-aws/templates/db-statefulset.yaml b/aws/my-recipes-chart-aws/templates/db-statefulset.yaml deleted file mode 100644 index 93af59a..0000000 --- a/aws/my-recipes-chart-aws/templates/db-statefulset.yaml +++ /dev/null @@ -1,89 +0,0 @@ -{{- if not .Values.database }} -{{- /* Only deploy in-cluster PostgreSQL if external database is not configured */ -}} -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ .Release.Name }}-{{ .Values.postgres.name }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-{{ .Values.postgres.name }} - component: database -spec: - serviceName: {{ .Release.Name }}-{{ .Values.postgres.name }}-headless - replicas: 1 - selector: - matchLabels: - app: {{ .Release.Name }}-{{ .Values.postgres.name }} - template: - metadata: - labels: - app: {{ .Release.Name }}-{{ .Values.postgres.name }} - component: database - spec: - containers: - - name: postgres - image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}" - imagePullPolicy: {{ .Values.postgres.image.pullPolicy }} - ports: - - containerPort: {{ .Values.postgres.port }} - name: postgres - protocol: TCP - env: - - name: POSTGRES_USER - value: {{ .Values.postgres.user | quote }} - - name: POSTGRES_PASSWORD - value: {{ .Values.postgres.password | quote }} - - name: POSTGRES_DB - value: {{ .Values.postgres.database | quote }} - - name: PGDATA - value: /var/lib/postgresql/data/pgdata - volumeMounts: - - name: data - mountPath: /var/lib/postgresql/data - - name: init-sql - mountPath: /docker-entrypoint-initdb.d - livenessProbe: - exec: - command: - - /bin/sh - - -c - - pg_isready -U {{ .Values.postgres.user }} - initialDelaySeconds: 30 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - readinessProbe: - exec: - command: - - /bin/sh - - -c - - pg_isready -U {{ .Values.postgres.user }} - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 3 - failureThreshold: 2 - resources: - requests: - cpu: {{ .Values.postgres.resources.requests.cpu }} - memory: {{ .Values.postgres.resources.requests.memory }} - limits: - cpu: {{ .Values.postgres.resources.limits.cpu }} - memory: {{ .Values.postgres.resources.limits.memory }} - volumes: - - name: init-sql - configMap: - name: {{ .Release.Name }}-db-schema - volumeClaimTemplates: - - metadata: - name: data - spec: - accessModes: - - {{ .Values.postgres.persistence.accessMode }} - resources: - requests: - storage: {{ .Values.postgres.persistence.size }} - {{- if .Values.postgres.persistence.storageClass }} - storageClassName: {{ .Values.postgres.persistence.storageClass | quote }} - {{- end }} -{{- end }} - diff --git a/aws/my-recipes-chart-aws/templates/frontend-deployment.yaml b/aws/my-recipes-chart-aws/templates/frontend-deployment.yaml deleted file mode 100644 index 8973e53..0000000 --- a/aws/my-recipes-chart-aws/templates/frontend-deployment.yaml +++ /dev/null @@ -1,57 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Release.Name }}-{{ .Values.frontend.name }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-{{ .Values.frontend.name }} - component: frontend -spec: - replicas: {{ .Values.frontend.replicaCount }} - selector: - matchLabels: - app: {{ .Release.Name }}-{{ .Values.frontend.name }} - template: - metadata: - labels: - app: {{ .Release.Name }}-{{ .Values.frontend.name }} - component: frontend - spec: - containers: - - name: {{ .Values.frontend.name }} - image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}" - imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} - ports: - - containerPort: {{ .Values.frontend.service.targetPort }} - name: http - protocol: TCP - {{- with .Values.frontend.env }} - env: - {{- range $key, $value := . }} - - name: {{ $key }} - value: {{ $value | quote }} - {{- end }} - {{- end }} - livenessProbe: - httpGet: - path: / - port: http - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - readinessProbe: - httpGet: - path: / - port: http - initialDelaySeconds: 5 - periodSeconds: 5 - timeoutSeconds: 3 - failureThreshold: 2 - resources: - requests: - cpu: {{ .Values.frontend.resources.requests.cpu }} - memory: {{ .Values.frontend.resources.requests.memory }} - limits: - cpu: {{ .Values.frontend.resources.limits.cpu }} - memory: {{ .Values.frontend.resources.limits.memory }} diff --git a/aws/my-recipes-chart-aws/templates/frontend-service.yaml b/aws/my-recipes-chart-aws/templates/frontend-service.yaml deleted file mode 100644 index 9427830..0000000 --- a/aws/my-recipes-chart-aws/templates/frontend-service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ .Release.Name }}-{{ .Values.frontend.name }} - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-{{ .Values.frontend.name }} - component: frontend -spec: - type: {{ .Values.frontend.service.type }} - ports: - - port: {{ .Values.frontend.service.port }} - targetPort: {{ .Values.frontend.service.targetPort }} - protocol: TCP - name: http - selector: - app: {{ .Release.Name }}-{{ .Values.frontend.name }} diff --git a/aws/my-recipes-chart-aws/templates/ingress.yaml b/aws/my-recipes-chart-aws/templates/ingress.yaml deleted file mode 100644 index d106c59..0000000 --- a/aws/my-recipes-chart-aws/templates/ingress.yaml +++ /dev/null @@ -1,89 +0,0 @@ -{{- if .Values.frontend.ingress.enabled }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ .Release.Name }}-frontend - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-frontend - component: frontend - {{- with .Values.frontend.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if .Values.frontend.ingress.className }} - ingressClassName: {{ .Values.frontend.ingress.className }} - {{- end }} - rules: - {{- range .Values.frontend.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - pathType: {{ .pathType }} - backend: - service: - name: {{ $.Release.Name }}-{{ $.Values.frontend.name }} - port: - number: {{ $.Values.frontend.service.port }} - {{- end }} - {{- end }} - {{- if .Values.frontend.ingress.tls }} - tls: - {{- range .Values.frontend.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} -{{- end }} - ---- - -{{- if .Values.backend.ingress.enabled }} -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: {{ .Release.Name }}-backend - namespace: {{ .Values.global.namespace }} - labels: - app: {{ .Release.Name }}-backend - component: backend - {{- with .Values.backend.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if .Values.backend.ingress.className }} - ingressClassName: {{ .Values.backend.ingress.className }} - {{- end }} - rules: - {{- range .Values.backend.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - pathType: {{ .pathType }} - backend: - service: - name: {{ $.Release.Name }}-{{ $.Values.backend.name }} - port: - number: {{ $.Values.backend.service.port }} - {{- end }} - {{- end }} - {{- if .Values.backend.ingress.tls }} - tls: - {{- range .Values.backend.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} -{{- end }} diff --git a/aws/my-recipes-chart-aws/values.yaml b/aws/my-recipes-chart-aws/values.yaml deleted file mode 100644 index 31d7804..0000000 --- a/aws/my-recipes-chart-aws/values.yaml +++ /dev/null @@ -1,182 +0,0 @@ -global: - namespace: my-apps - imagePullSecrets: [] - -# Backend configuration -backend: - name: backend - replicaCount: 2 - image: - repository: harbor.dvirlabs.com/my-apps/my-recipes-backend - pullPolicy: IfNotPresent - tag: "latest" - - service: - type: ClusterIP - port: 8000 - targetPort: 8000 - - resources: - requests: - cpu: 100m - memory: 128Mi - limits: - cpu: 500m - memory: 512Mi - - env: - PYTHONUNBUFFERED: "1" - - # Secrets are created in db-secret.yaml - # These are passed via envFrom secretRef - - ingress: - enabled: true - className: "alb" - annotations: - alb.ingress.kubernetes.io/scheme: internet-facing - alb.ingress.kubernetes.io/target-type: ip - alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' - alb.ingress.kubernetes.io/certificate-arn: "" # Set in project-specific values - hosts: - - host: api-my-recipes.dvirlabs.com - paths: - - path: / - pathType: Prefix - tls: - - secretName: api-my-recipes-tls - hosts: - - api-my-recipes.dvirlabs.com - -# Frontend configuration -frontend: - name: frontend - replicaCount: 2 - image: - repository: harbor.dvirlabs.com/my-apps/my-recipes-frontend - pullPolicy: IfNotPresent - tag: "latest" - - service: - type: ClusterIP - port: 80 - targetPort: 80 - - env: - API_BASE: "https://api-my-recipes.dvirlabs.com" - - resources: - requests: - cpu: 50m - memory: 64Mi - limits: - cpu: 200m - memory: 256Mi - - ingress: - enabled: true - className: "alb" - annotations: - alb.ingress.kubernetes.io/scheme: internet-facing - alb.ingress.kubernetes.io/target-type: ip - alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' - alb.ingress.kubernetes.io/certificate-arn: "" # Set in project-specific values - hosts: - - host: my-recipes.dvirlabs.com - paths: - - path: / - pathType: Prefix - tls: - - secretName: my-recipes-tls - hosts: - - my-recipes.dvirlabs.com - externalUrl: "https://my-recipes.dvirlabs.com" - -# PostgreSQL configuration -postgres: - name: db - image: - repository: postgres - tag: "16-alpine" - pullPolicy: IfNotPresent - - user: recipes_user - password: recipes_password - database: recipes_db - port: 5432 - - service: - type: ClusterIP - port: 5432 - targetPort: 5432 - - persistence: - enabled: true - accessMode: ReadWriteOnce - storageClass: "nfs-client" - size: 10Gi - - resources: - requests: - cpu: 100m - memory: 256Mi - limits: - cpu: 1000m - memory: 1Gi - -# OAuth Configuration -oauth: - google: - clientId: "143092846986-hsi59m0on2c9rb5qrdoejfceieao2ioc.apps.googleusercontent.com" - clientSecret: "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" - redirectUri: "https://api-my-recipes.dvirlabs.com/auth/google/callback" - - azure: - clientId: "db244cf5-eb11-4738-a2ea-5b0716c9ec0a" - clientSecret: "Zad8Q~qRBxaQq8up0lLXAq4pHzrVM2JFGFJhHaDp" - tenantId: "consumers" - redirectUri: "https://api-my-recipes.dvirlabs.com/auth/azure/callback" - -# Email Configuration -email: - smtpHost: "smtp.gmail.com" - smtpPort: "587" - smtpUser: "dvirlabs@gmail.com" - smtpPassword: "agaanrhbbazbdytv" - smtpFrom: "dvirlabs@gmail.com" - -# S3 Backup Configuration -s3: - endpoint: "https://s3.amazonaws.com" # Can be overridden for specific regions - accessKey: "" # Set this in project-specific values.yaml - secretKey: "" # Set this in project-specific values.yaml - bucketName: "" # Set this in project-specific values.yaml - region: "us-east-1" # Set this in project-specific values.yaml - backupInterval: "weekly" # Options: test (1 min), daily, weekly - -# Admin User Configuration -admin: - username: "admin" - email: "admin@example.com" - password: "admin123" # Change this in production! - firstName: "Admin" - lastName: "User" - displayName: "Admin User" - -# Ingress configuration -ingress: - enabled: false # Individual frontend/backend ingress resources handle routing instead - className: "nginx" - annotations: - cert-manager.io/cluster-issuer: "letsencrypt-prod" - hosts: - - host: my-recipes.dvirlabs.com - paths: - - path: / - pathType: Prefix - backend: frontend - tls: - - secretName: recipes-tls - hosts: - - my-recipes.dvirlabs.com - diff --git a/aws/values.yaml b/aws/values.yaml deleted file mode 100644 index e526c3d..0000000 --- a/aws/values.yaml +++ /dev/null @@ -1,110 +0,0 @@ -# Project-specific values for AWS EKS deployment -# This file overrides the base values in my-recipes-chart/values.yaml - -global: - namespace: my-apps - -# Backend configuration -backend: - replicaCount: 2 - image: - repository: 430842105273.dkr.ecr.eu-central-1.amazonaws.com/my-recipes-backend # Update with your ECR repository - tag: "latest" - - ingress: - className: "alb" - annotations: - alb.ingress.kubernetes.io/scheme: internet-facing - alb.ingress.kubernetes.io/target-type: ip - alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' - # Add your ACM certificate ARN below if you have one - # alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:..." - hosts: - - host: api-my-recipes.aws-dvirlabs.com - paths: - - path: / - pathType: Prefix - -# Frontend configuration -frontend: - replicaCount: 2 - image: - repository: 430842105273.dkr.ecr.eu-central-1.amazonaws.com/my-recipes-frontend # Update with your ECR repository - tag: "latest" - - env: - API_BASE: "https://api-my-recipes.aws-dvirlabs.com" - - ingress: - className: "alb" - annotations: - alb.ingress.kubernetes.io/scheme: internet-facing - alb.ingress.kubernetes.io/target-type: ip - alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' - # Add your ACM certificate ARN below if you have one - # alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:..." - hosts: - - host: my-recipes.aws-dvirlabs.com - paths: - - path: / - pathType: Prefix - - externalUrl: "https://my-recipes.aws-dvirlabs.com" - -# PostgreSQL configuration -postgres: - # For AWS RDS, set this to use external database - # Leave enabled: true to use in-cluster database - enabled: false # Set to false if using RDS - - # If using RDS, these values are ignored but kept for reference - persistence: - storageClass: "gp3" # EKS default storage class - size: 20Gi - -# OAuth Configuration -oauth: - google: - clientId: "143092846986-hsi59m0on2c9rb5qrdoejfceieao2ioc.apps.googleusercontent.com" - clientSecret: "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" - redirectUri: "https://api-my-recipes.aws-dvirlabs.com/auth/google/callback" - - azure: - clientId: "db244cf5-eb11-4738-a2ea-5b0716c9ec0a" - clientSecret: "Zad8Q~qRBxaQq8up0lLXAq4pHzrVM2JFGFJhHaDp" - tenantId: "consumers" - redirectUri: "https://api-my-recipes.aws-dvirlabs.com/auth/azure/callback" - -# Email Configuration -email: - smtpHost: "smtp.gmail.com" - smtpPort: "587" - smtpUser: "dvirlabs@gmail.com" - smtpPassword: "agaanrhbbazbdytv" - smtpFrom: "dvirlabs@gmail.com" - -# S3 Backup Configuration for AWS -s3: - endpoint: "https://s3.eu-central-1.amazonaws.com" # Update with your region - accessKey: "AKIAXXXXXXXXXXXXXXXX" # Replace with your AWS Access Key - secretKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Replace with your AWS Secret Key - bucketName: "my-recipes-backups" # Update with your S3 bucket name - region: "eu-central-1" # Update with your region - backupInterval: "weekly" - -# Admin User Configuration -admin: - username: "admin" - email: "dvirlabs@gmail.com" - password: "AdminPassword123!" # Change this after first login! - firstName: "Dvir" - lastName: "Admin" - displayName: "Dvir Admin" - -# Database connection for AWS RDS (used when postgres.enabled: false) -database: - host: "my-recipes-rds.chw4omcguqv7.eu-central-1.rds.amazonaws.com" - port: "5432" - name: "recipes_db" - user: "recipes_user" - password: "recipes_password" # Store securely in AWS Secrets Manager in production From 16938f42bf865b985243a68ea11a3df420ecbd7d Mon Sep 17 00:00:00 2001 From: dvirlabs <114520947+dvirlabs@users.noreply.github.com> Date: Mon, 5 Jan 2026 21:55:23 +0200 Subject: [PATCH 2/2] Update schema.sql --- aws/final-app/my-recipes-chart-aws/Chart.yaml | 14 ++ .../add-missing-tables-configmap.yaml | 45 +++++ .../templates/add-missing-tables-job.yaml | 49 +++++ .../templates/admin-init-configmap.yaml | 99 ++++++++++ .../templates/admin-init-job.yaml | 75 ++++++++ .../templates/app-secrets.yaml | 35 ++++ .../templates/backend-deployment.yaml | 119 ++++++++++++ .../templates/backend-service.yaml | 17 ++ .../templates/db-migration-configmap.yaml | 54 ++++++ .../templates/db-migration-job.yaml | 69 +++++++ .../templates/db-schema-configmap.yaml | 134 +++++++++++++ .../templates/db-secret.yaml | 23 +++ .../templates/db-service.yaml | 39 ++++ .../templates/db-statefulset.yaml | 89 +++++++++ .../templates/frontend-deployment.yaml | 57 ++++++ .../templates/frontend-service.yaml | 17 ++ .../templates/ingress.yaml | 89 +++++++++ .../my-recipes-chart-aws/values.yaml | 182 ++++++++++++++++++ aws/final-app/values.yaml | 110 +++++++++++ 19 files changed, 1316 insertions(+) create mode 100644 aws/final-app/my-recipes-chart-aws/Chart.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-job.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/admin-init-configmap.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/admin-init-job.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/app-secrets.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/backend-deployment.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/backend-service.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/db-migration-configmap.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/db-migration-job.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/db-schema-configmap.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/db-secret.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/db-service.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/db-statefulset.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/frontend-deployment.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/frontend-service.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/templates/ingress.yaml create mode 100644 aws/final-app/my-recipes-chart-aws/values.yaml create mode 100644 aws/final-app/values.yaml diff --git a/aws/final-app/my-recipes-chart-aws/Chart.yaml b/aws/final-app/my-recipes-chart-aws/Chart.yaml new file mode 100644 index 0000000..86c815b --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +name: my-recipes +description: Complete recipe management application with PostgreSQL, FastAPI backend, and React frontend +type: application +version: 1.0.0 +appVersion: "1.0.0" +keywords: + - recipes + - fastapi + - react + - postgresql +maintainers: + - name: Development Team + diff --git a/aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml b/aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml new file mode 100644 index 0000000..d15cad9 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-configmap.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-add-missing-tables + namespace: {{ .Values.global.namespace }} +data: + add-tables.sql: | + -- Create grocery lists table + CREATE TABLE IF NOT EXISTS grocery_lists ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + items TEXT[] NOT NULL DEFAULT '{}', + owner_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + is_pinned BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + -- Create grocery list shares table + CREATE TABLE IF NOT EXISTS grocery_list_shares ( + id SERIAL PRIMARY KEY, + list_id INTEGER NOT NULL REFERENCES grocery_lists(id) ON DELETE CASCADE, + shared_with_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + can_edit BOOLEAN DEFAULT FALSE, + shared_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(list_id, shared_with_user_id) + ); + + CREATE INDEX IF NOT EXISTS idx_grocery_lists_owner_id ON grocery_lists (owner_id); + CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_list_id ON grocery_list_shares (list_id); + CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_user_id ON grocery_list_shares (shared_with_user_id); + + -- Create notifications table + CREATE TABLE IF NOT EXISTS notifications ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + type TEXT NOT NULL, + message TEXT NOT NULL, + related_id INTEGER, + is_read BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications (user_id); + CREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications (is_read); diff --git a/aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-job.yaml b/aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-job.yaml new file mode 100644 index 0000000..e0ca1bc --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/add-missing-tables-job.yaml @@ -0,0 +1,49 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-add-missing-tables + namespace: {{ .Values.global.namespace }} + annotations: + "helm.sh/hook": post-upgrade + "helm.sh/hook-weight": "6" + "helm.sh/hook-delete-policy": before-hook-creation +spec: + template: + spec: + restartPolicy: Never + containers: + - name: add-tables + image: postgres:16-alpine + env: + - name: PGHOST + value: {{ .Release.Name }}-db + - name: PGPORT + value: "{{ .Values.postgres.port }}" + - name: PGDATABASE + value: {{ .Values.postgres.database }} + - name: PGUSER + value: {{ .Values.postgres.user }} + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PASSWORD + command: + - sh + - -c + - | + echo "Waiting for database to be ready..." + until pg_isready -h $PGHOST -p $PGPORT -U $PGUSER; do + echo "Database not ready, waiting..." + sleep 2 + done + echo "Database ready, adding missing tables..." + psql -v ON_ERROR_STOP=1 -f /sql/add-tables.sql + echo "Tables added successfully!" + volumeMounts: + - name: sql + mountPath: /sql + volumes: + - name: sql + configMap: + name: {{ .Release.Name }}-add-missing-tables diff --git a/aws/final-app/my-recipes-chart-aws/templates/admin-init-configmap.yaml b/aws/final-app/my-recipes-chart-aws/templates/admin-init-configmap.yaml new file mode 100644 index 0000000..7bda3cd --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/admin-init-configmap.yaml @@ -0,0 +1,99 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-admin-init + namespace: {{ .Values.global.namespace }} +data: + create-admin.py: | + #!/usr/bin/env python3 + import os + import sys + import psycopg2 + import bcrypt + from time import sleep + + def wait_for_db(): + """Wait for database to be ready""" + max_retries = 30 + retry_count = 0 + + while retry_count < max_retries: + try: + conn = psycopg2.connect( + host=os.environ['DB_HOST'], + port=os.environ['DB_PORT'], + database=os.environ['DB_NAME'], + user=os.environ['DB_USER'], + password=os.environ['DB_PASSWORD'] + ) + conn.close() + print("✓ Database is ready") + return True + except Exception as e: + retry_count += 1 + print(f"Waiting for database... ({retry_count}/{max_retries})") + sleep(2) + + print("✗ Database connection timeout") + return False + + def create_admin_user(): + """Create admin user if not exists""" + try: + # Hash the password + password = os.environ.get('ADMIN_PASSWORD', 'admin123') + password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8') + + # Connect to database + conn = psycopg2.connect( + host=os.environ['DB_HOST'], + port=os.environ['DB_PORT'], + database=os.environ['DB_NAME'], + user=os.environ['DB_USER'], + password=os.environ['DB_PASSWORD'] + ) + cur = conn.cursor() + + # Insert admin user + cur.execute(""" + INSERT INTO users (username, email, password_hash, first_name, last_name, display_name, is_admin) + VALUES (%s, %s, %s, %s, %s, %s, %s) + ON CONFLICT (username) DO UPDATE SET + email = EXCLUDED.email, + password_hash = EXCLUDED.password_hash, + first_name = EXCLUDED.first_name, + last_name = EXCLUDED.last_name, + display_name = EXCLUDED.display_name, + is_admin = EXCLUDED.is_admin + """, ( + os.environ.get('ADMIN_USERNAME', 'admin'), + os.environ.get('ADMIN_EMAIL', 'admin@myrecipes.local'), + password_hash, + os.environ.get('ADMIN_FIRST_NAME', 'Admin'), + os.environ.get('ADMIN_LAST_NAME', 'User'), + os.environ.get('ADMIN_DISPLAY_NAME', 'מנהל'), + True + )) + + conn.commit() + cur.close() + conn.close() + + print(f"✓ Admin user '{os.environ.get('ADMIN_USERNAME', 'admin')}' created/updated successfully") + return True + + except Exception as e: + print(f"✗ Error creating admin user: {e}") + return False + + if __name__ == "__main__": + print("Starting admin user initialization...") + + if not wait_for_db(): + sys.exit(1) + + if not create_admin_user(): + sys.exit(1) + + print("✓ Admin user initialization completed") + sys.exit(0) diff --git a/aws/final-app/my-recipes-chart-aws/templates/admin-init-job.yaml b/aws/final-app/my-recipes-chart-aws/templates/admin-init-job.yaml new file mode 100644 index 0000000..511ec36 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/admin-init-job.yaml @@ -0,0 +1,75 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-admin-init-{{ .Release.Revision }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-admin-init + component: init + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-weight": "10" + "helm.sh/hook-delete-policy": before-hook-creation +spec: + ttlSecondsAfterFinished: 300 + template: + metadata: + labels: + app: {{ .Release.Name }}-admin-init + spec: + restartPolicy: Never + containers: + - name: admin-init + image: python:3.12-slim + command: + - /bin/sh + - -c + - | + pip install --no-cache-dir psycopg2-binary bcrypt > /dev/null 2>&1 + python3 /scripts/create-admin.py + env: + - name: DB_HOST + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_HOST + - name: DB_PORT + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PORT + - name: DB_NAME + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_NAME + - name: DB_USER + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PASSWORD + - name: ADMIN_USERNAME + value: {{ .Values.admin.username | quote }} + - name: ADMIN_EMAIL + value: {{ .Values.admin.email | quote }} + - name: ADMIN_PASSWORD + value: {{ .Values.admin.password | quote }} + - name: ADMIN_FIRST_NAME + value: {{ .Values.admin.firstName | quote }} + - name: ADMIN_LAST_NAME + value: {{ .Values.admin.lastName | quote }} + - name: ADMIN_DISPLAY_NAME + value: {{ .Values.admin.displayName | quote }} + volumeMounts: + - name: init-script + mountPath: /scripts + volumes: + - name: init-script + configMap: + name: {{ .Release.Name }}-admin-init + defaultMode: 0755 diff --git a/aws/final-app/my-recipes-chart-aws/templates/app-secrets.yaml b/aws/final-app/my-recipes-chart-aws/templates/app-secrets.yaml new file mode 100644 index 0000000..93285f3 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/app-secrets.yaml @@ -0,0 +1,35 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-app-secrets + namespace: {{ .Values.global.namespace }} +type: Opaque +stringData: + # Google OAuth + GOOGLE_CLIENT_ID: {{ .Values.oauth.google.clientId | quote }} + GOOGLE_CLIENT_SECRET: {{ .Values.oauth.google.clientSecret | quote }} + GOOGLE_REDIRECT_URI: {{ .Values.oauth.google.redirectUri | quote }} + + # Microsoft Entra ID (Azure AD) OAuth + AZURE_CLIENT_ID: {{ .Values.oauth.azure.clientId | quote }} + AZURE_CLIENT_SECRET: {{ .Values.oauth.azure.clientSecret | quote }} + AZURE_TENANT_ID: {{ .Values.oauth.azure.tenantId | quote }} + AZURE_REDIRECT_URI: {{ .Values.oauth.azure.redirectUri | quote }} + + # Email Configuration + SMTP_HOST: {{ .Values.email.smtpHost | quote }} + SMTP_PORT: {{ .Values.email.smtpPort | quote }} + SMTP_USER: {{ .Values.email.smtpUser | quote }} + SMTP_PASSWORD: {{ .Values.email.smtpPassword | quote }} + SMTP_FROM: {{ .Values.email.smtpFrom | quote }} + + # Frontend URL for redirects + FRONTEND_URL: {{ .Values.frontend.externalUrl | quote }} + + # S3 Backup Configuration + S3_ENDPOINT: {{ .Values.s3.endpoint | quote }} + S3_ACCESS_KEY: {{ .Values.s3.accessKey | quote }} + S3_SECRET_KEY: {{ .Values.s3.secretKey | quote }} + S3_BUCKET_NAME: {{ .Values.s3.bucketName | quote }} + S3_REGION: {{ .Values.s3.region | quote }} + BACKUP_INTERVAL: {{ .Values.s3.backupInterval | quote }} diff --git a/aws/final-app/my-recipes-chart-aws/templates/backend-deployment.yaml b/aws/final-app/my-recipes-chart-aws/templates/backend-deployment.yaml new file mode 100644 index 0000000..b7379bd --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/backend-deployment.yaml @@ -0,0 +1,119 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-{{ .Values.backend.name }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-{{ .Values.backend.name }} + component: backend +spec: + replicas: {{ .Values.backend.replicaCount }} + selector: + matchLabels: + app: {{ .Release.Name }}-{{ .Values.backend.name }} + template: + metadata: + labels: + app: {{ .Release.Name }}-{{ .Values.backend.name }} + component: backend + spec: + initContainers: + - name: db-migration + image: postgres:16-alpine + command: + - /bin/sh + - -c + - | + echo "Waiting for database to be ready..." + until pg_isready -h $DB_HOST -U $DB_USER; do + echo "Database not ready, waiting..." + sleep 2 + done + echo "Database is ready, running migration..." + PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -U $DB_USER -d $DB_NAME -f /migration/migrate.sql + echo "Migration completed successfully" + env: + - name: DB_HOST + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_HOST + - name: DB_PORT + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PORT + - name: DB_NAME + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_NAME + - name: DB_USER + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PASSWORD + volumeMounts: + - name: migration-script + mountPath: /migration + containers: + - name: {{ .Values.backend.name }} + image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}" + imagePullPolicy: {{ .Values.backend.image.pullPolicy }} + ports: + - containerPort: {{ .Values.backend.service.targetPort }} + name: http + protocol: TCP + env: + {{- if .Values.backend.env }} + {{- range $key, $value := .Values.backend.env }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + envFrom: + - secretRef: + name: {{ .Release.Name }}-db-credentials + - secretRef: + name: {{ .Release.Name }}-app-secrets + startupProbe: + httpGet: + path: /docs + port: http + initialDelaySeconds: 15 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 30 + livenessProbe: + httpGet: + path: /docs + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /docs + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 2 + resources: + requests: + cpu: {{ .Values.backend.resources.requests.cpu }} + memory: {{ .Values.backend.resources.requests.memory }} + limits: + cpu: {{ .Values.backend.resources.limits.cpu }} + memory: {{ .Values.backend.resources.limits.memory }} + volumes: + - name: migration-script + configMap: + name: {{ .Release.Name }}-db-migration + diff --git a/aws/final-app/my-recipes-chart-aws/templates/backend-service.yaml b/aws/final-app/my-recipes-chart-aws/templates/backend-service.yaml new file mode 100644 index 0000000..6608df6 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/backend-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-{{ .Values.backend.name }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-{{ .Values.backend.name }} + component: backend +spec: + type: {{ .Values.backend.service.type }} + ports: + - port: {{ .Values.backend.service.port }} + targetPort: {{ .Values.backend.service.targetPort }} + protocol: TCP + name: http + selector: + app: {{ .Release.Name }}-{{ .Values.backend.name }} diff --git a/aws/final-app/my-recipes-chart-aws/templates/db-migration-configmap.yaml b/aws/final-app/my-recipes-chart-aws/templates/db-migration-configmap.yaml new file mode 100644 index 0000000..5a7c4da --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/db-migration-configmap.yaml @@ -0,0 +1,54 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-db-migration + namespace: {{ .Values.global.namespace }} +data: + migrate.sql: | + -- Add made_by column to recipes if it doesn't exist + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'recipes' AND column_name = 'made_by' + ) THEN + ALTER TABLE recipes ADD COLUMN made_by TEXT; + END IF; + END $$; + + -- Create index if it doesn't exist + CREATE INDEX IF NOT EXISTS idx_recipes_made_by ON recipes (made_by); + + -- Add is_admin column to users if it doesn't exist + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'is_admin' + ) THEN + ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT FALSE; + END IF; + END $$; + + -- Add auth_provider column to users if it doesn't exist + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'auth_provider' + ) THEN + ALTER TABLE users ADD COLUMN auth_provider TEXT DEFAULT 'local'; + END IF; + END $$; + + -- Verify recipes schema + SELECT column_name, data_type + FROM information_schema.columns + WHERE table_name = 'recipes' + ORDER BY ordinal_position; + + -- Verify users schema + SELECT column_name, data_type + FROM information_schema.columns + WHERE table_name = 'users' + ORDER BY ordinal_position; diff --git a/aws/final-app/my-recipes-chart-aws/templates/db-migration-job.yaml b/aws/final-app/my-recipes-chart-aws/templates/db-migration-job.yaml new file mode 100644 index 0000000..f153342 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/db-migration-job.yaml @@ -0,0 +1,69 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ .Release.Name }}-db-migration-{{ .Release.Revision }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-db-migration + component: migration + annotations: + "helm.sh/hook": post-upgrade,post-install + "helm.sh/hook-weight": "5" + "helm.sh/hook-delete-policy": before-hook-creation +spec: + ttlSecondsAfterFinished: 300 + template: + metadata: + labels: + app: {{ .Release.Name }}-db-migration + spec: + restartPolicy: Never + containers: + - name: migrate + image: postgres:16-alpine + command: + - /bin/sh + - -c + - | + echo "Waiting for database to be ready..." + until pg_isready -h $DB_HOST -U $DB_USER; do + echo "Database not ready, waiting..." + sleep 2 + done + echo "Database is ready, running migration..." + PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -U $DB_USER -d $DB_NAME -f /migration/migrate.sql + echo "Migration completed successfully" + env: + - name: DB_HOST + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_HOST + - name: DB_PORT + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PORT + - name: DB_NAME + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_NAME + - name: DB_USER + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_USER + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Release.Name }}-db-credentials + key: DB_PASSWORD + volumeMounts: + - name: migration-script + mountPath: /migration + volumes: + - name: migration-script + configMap: + name: {{ .Release.Name }}-db-migration + diff --git a/aws/final-app/my-recipes-chart-aws/templates/db-schema-configmap.yaml b/aws/final-app/my-recipes-chart-aws/templates/db-schema-configmap.yaml new file mode 100644 index 0000000..c6ee6dc --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/db-schema-configmap.yaml @@ -0,0 +1,134 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-db-schema + namespace: {{ .Values.global.namespace }} +data: + schema.sql: | + -- Create users table + CREATE TABLE IF NOT EXISTS users ( + id SERIAL PRIMARY KEY, + username TEXT UNIQUE NOT NULL, + email TEXT UNIQUE NOT NULL, + password_hash TEXT NOT NULL, + first_name TEXT, + last_name TEXT, + display_name TEXT NOT NULL, + is_admin BOOLEAN DEFAULT FALSE, + auth_provider TEXT DEFAULT 'local', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + CREATE INDEX IF NOT EXISTS idx_users_username ON users (username); + CREATE INDEX IF NOT EXISTS idx_users_email ON users (email); + + -- Create recipes table (matching backend schema with TEXT[] arrays) + CREATE TABLE IF NOT EXISTS recipes ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + meal_type TEXT NOT NULL, -- breakfast / lunch / dinner / snack + time_minutes INTEGER NOT NULL, + tags TEXT[] NOT NULL DEFAULT '{}', -- {"מהיר", "בריא"} + ingredients TEXT[] NOT NULL DEFAULT '{}', -- {"ביצה", "עגבניה", "מלח"} + steps TEXT[] NOT NULL DEFAULT '{}', -- {"לחתוך", "לבשל", ...} + image TEXT, -- Base64-encoded image or image URL + made_by TEXT, -- Person who created this recipe version + user_id INTEGER REFERENCES users(id) ON DELETE SET NULL, -- Recipe owner + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + -- Indexes for filters + CREATE INDEX IF NOT EXISTS idx_recipes_meal_type + ON recipes (meal_type); + + CREATE INDEX IF NOT EXISTS idx_recipes_time_minutes + ON recipes (time_minutes); + + CREATE INDEX IF NOT EXISTS idx_recipes_made_by + ON recipes (made_by); + + CREATE INDEX IF NOT EXISTS idx_recipes_user_id + ON recipes (user_id); + + -- Add new columns to existing users table + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'first_name' + ) THEN + ALTER TABLE users ADD COLUMN first_name TEXT; + END IF; + END $$; + + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'last_name' + ) THEN + ALTER TABLE users ADD COLUMN last_name TEXT; + END IF; + END $$; + + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'display_name' + ) THEN + ALTER TABLE users ADD COLUMN display_name TEXT; + -- Set display_name to username for existing users + UPDATE users SET display_name = username WHERE display_name IS NULL; + ALTER TABLE users ALTER COLUMN display_name SET NOT NULL; + END IF; + END $$; + + DO $$ + BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = 'users' AND column_name = 'is_admin' + ) THEN + ALTER TABLE users ADD COLUMN is_admin BOOLEAN DEFAULT FALSE; + END IF; + END $$; + + -- Create grocery lists table + CREATE TABLE IF NOT EXISTS grocery_lists ( + id SERIAL PRIMARY KEY, + name TEXT NOT NULL, + items TEXT[] NOT NULL DEFAULT '{}', + owner_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + is_pinned BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + -- Create grocery list shares table + CREATE TABLE IF NOT EXISTS grocery_list_shares ( + id SERIAL PRIMARY KEY, + list_id INTEGER NOT NULL REFERENCES grocery_lists(id) ON DELETE CASCADE, + shared_with_user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + can_edit BOOLEAN DEFAULT FALSE, + shared_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + UNIQUE(list_id, shared_with_user_id) + ); + + CREATE INDEX IF NOT EXISTS idx_grocery_lists_owner_id ON grocery_lists (owner_id); + CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_list_id ON grocery_list_shares (list_id); + CREATE INDEX IF NOT EXISTS idx_grocery_list_shares_user_id ON grocery_list_shares (shared_with_user_id); + + -- Create notifications table + CREATE TABLE IF NOT EXISTS notifications ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + type TEXT NOT NULL, + message TEXT NOT NULL, + related_id INTEGER, + is_read BOOLEAN DEFAULT FALSE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + + CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications (user_id); + CREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications (is_read); diff --git a/aws/final-app/my-recipes-chart-aws/templates/db-secret.yaml b/aws/final-app/my-recipes-chart-aws/templates/db-secret.yaml new file mode 100644 index 0000000..aef2e21 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/db-secret.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-db-credentials + namespace: {{ .Values.global.namespace }} +type: Opaque +stringData: + {{- if .Values.database }} + # External database (e.g., AWS RDS) + DB_HOST: {{ .Values.database.host | quote }} + DB_PORT: {{ .Values.database.port | quote }} + DB_NAME: {{ .Values.database.name | quote }} + DB_USER: {{ .Values.database.user | quote }} + DB_PASSWORD: {{ .Values.database.password | quote }} + {{- else }} + # In-cluster PostgreSQL + DB_HOST: {{ printf "%s-%s-headless.%s.svc.cluster.local" .Release.Name .Values.postgres.name .Values.global.namespace }} + DB_PORT: "{{ .Values.postgres.port }}" + DB_NAME: {{ .Values.postgres.database | quote }} + DB_USER: {{ .Values.postgres.user | quote }} + DB_PASSWORD: {{ .Values.postgres.password | quote }} + {{- end }} + diff --git a/aws/final-app/my-recipes-chart-aws/templates/db-service.yaml b/aws/final-app/my-recipes-chart-aws/templates/db-service.yaml new file mode 100644 index 0000000..c4704d3 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/db-service.yaml @@ -0,0 +1,39 @@ +{{- if not .Values.database }} +{{- /* Only deploy in-cluster PostgreSQL services if external database is not configured */ -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-{{ .Values.postgres.name }}-headless + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-{{ .Values.postgres.name }} + component: database +spec: + clusterIP: None + selector: + app: {{ .Release.Name }}-{{ .Values.postgres.name }} + ports: + - name: postgres + port: {{ .Values.postgres.port }} + targetPort: {{ .Values.postgres.port }} + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-{{ .Values.postgres.name }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-{{ .Values.postgres.name }} + component: database +spec: + type: {{ .Values.postgres.service.type }} + selector: + app: {{ .Release.Name }}-{{ .Values.postgres.name }} + ports: + - name: postgres + port: {{ .Values.postgres.service.port }} + targetPort: {{ .Values.postgres.port }} + protocol: TCP +{{- end }} + diff --git a/aws/final-app/my-recipes-chart-aws/templates/db-statefulset.yaml b/aws/final-app/my-recipes-chart-aws/templates/db-statefulset.yaml new file mode 100644 index 0000000..93af59a --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/db-statefulset.yaml @@ -0,0 +1,89 @@ +{{- if not .Values.database }} +{{- /* Only deploy in-cluster PostgreSQL if external database is not configured */ -}} +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }}-{{ .Values.postgres.name }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-{{ .Values.postgres.name }} + component: database +spec: + serviceName: {{ .Release.Name }}-{{ .Values.postgres.name }}-headless + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }}-{{ .Values.postgres.name }} + template: + metadata: + labels: + app: {{ .Release.Name }}-{{ .Values.postgres.name }} + component: database + spec: + containers: + - name: postgres + image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}" + imagePullPolicy: {{ .Values.postgres.image.pullPolicy }} + ports: + - containerPort: {{ .Values.postgres.port }} + name: postgres + protocol: TCP + env: + - name: POSTGRES_USER + value: {{ .Values.postgres.user | quote }} + - name: POSTGRES_PASSWORD + value: {{ .Values.postgres.password | quote }} + - name: POSTGRES_DB + value: {{ .Values.postgres.database | quote }} + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + volumeMounts: + - name: data + mountPath: /var/lib/postgresql/data + - name: init-sql + mountPath: /docker-entrypoint-initdb.d + livenessProbe: + exec: + command: + - /bin/sh + - -c + - pg_isready -U {{ .Values.postgres.user }} + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + exec: + command: + - /bin/sh + - -c + - pg_isready -U {{ .Values.postgres.user }} + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 2 + resources: + requests: + cpu: {{ .Values.postgres.resources.requests.cpu }} + memory: {{ .Values.postgres.resources.requests.memory }} + limits: + cpu: {{ .Values.postgres.resources.limits.cpu }} + memory: {{ .Values.postgres.resources.limits.memory }} + volumes: + - name: init-sql + configMap: + name: {{ .Release.Name }}-db-schema + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: + - {{ .Values.postgres.persistence.accessMode }} + resources: + requests: + storage: {{ .Values.postgres.persistence.size }} + {{- if .Values.postgres.persistence.storageClass }} + storageClassName: {{ .Values.postgres.persistence.storageClass | quote }} + {{- end }} +{{- end }} + diff --git a/aws/final-app/my-recipes-chart-aws/templates/frontend-deployment.yaml b/aws/final-app/my-recipes-chart-aws/templates/frontend-deployment.yaml new file mode 100644 index 0000000..8973e53 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/frontend-deployment.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-{{ .Values.frontend.name }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-{{ .Values.frontend.name }} + component: frontend +spec: + replicas: {{ .Values.frontend.replicaCount }} + selector: + matchLabels: + app: {{ .Release.Name }}-{{ .Values.frontend.name }} + template: + metadata: + labels: + app: {{ .Release.Name }}-{{ .Values.frontend.name }} + component: frontend + spec: + containers: + - name: {{ .Values.frontend.name }} + image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}" + imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} + ports: + - containerPort: {{ .Values.frontend.service.targetPort }} + name: http + protocol: TCP + {{- with .Values.frontend.env }} + env: + {{- range $key, $value := . }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 2 + resources: + requests: + cpu: {{ .Values.frontend.resources.requests.cpu }} + memory: {{ .Values.frontend.resources.requests.memory }} + limits: + cpu: {{ .Values.frontend.resources.limits.cpu }} + memory: {{ .Values.frontend.resources.limits.memory }} diff --git a/aws/final-app/my-recipes-chart-aws/templates/frontend-service.yaml b/aws/final-app/my-recipes-chart-aws/templates/frontend-service.yaml new file mode 100644 index 0000000..9427830 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/frontend-service.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-{{ .Values.frontend.name }} + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-{{ .Values.frontend.name }} + component: frontend +spec: + type: {{ .Values.frontend.service.type }} + ports: + - port: {{ .Values.frontend.service.port }} + targetPort: {{ .Values.frontend.service.targetPort }} + protocol: TCP + name: http + selector: + app: {{ .Release.Name }}-{{ .Values.frontend.name }} diff --git a/aws/final-app/my-recipes-chart-aws/templates/ingress.yaml b/aws/final-app/my-recipes-chart-aws/templates/ingress.yaml new file mode 100644 index 0000000..d106c59 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/templates/ingress.yaml @@ -0,0 +1,89 @@ +{{- if .Values.frontend.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-frontend + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-frontend + component: frontend + {{- with .Values.frontend.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.frontend.ingress.className }} + ingressClassName: {{ .Values.frontend.ingress.className }} + {{- end }} + rules: + {{- range .Values.frontend.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ $.Release.Name }}-{{ $.Values.frontend.name }} + port: + number: {{ $.Values.frontend.service.port }} + {{- end }} + {{- end }} + {{- if .Values.frontend.ingress.tls }} + tls: + {{- range .Values.frontend.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} +{{- end }} + +--- + +{{- if .Values.backend.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ .Release.Name }}-backend + namespace: {{ .Values.global.namespace }} + labels: + app: {{ .Release.Name }}-backend + component: backend + {{- with .Values.backend.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.backend.ingress.className }} + ingressClassName: {{ .Values.backend.ingress.className }} + {{- end }} + rules: + {{- range .Values.backend.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ $.Release.Name }}-{{ $.Values.backend.name }} + port: + number: {{ $.Values.backend.service.port }} + {{- end }} + {{- end }} + {{- if .Values.backend.ingress.tls }} + tls: + {{- range .Values.backend.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} +{{- end }} diff --git a/aws/final-app/my-recipes-chart-aws/values.yaml b/aws/final-app/my-recipes-chart-aws/values.yaml new file mode 100644 index 0000000..31d7804 --- /dev/null +++ b/aws/final-app/my-recipes-chart-aws/values.yaml @@ -0,0 +1,182 @@ +global: + namespace: my-apps + imagePullSecrets: [] + +# Backend configuration +backend: + name: backend + replicaCount: 2 + image: + repository: harbor.dvirlabs.com/my-apps/my-recipes-backend + pullPolicy: IfNotPresent + tag: "latest" + + service: + type: ClusterIP + port: 8000 + targetPort: 8000 + + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + + env: + PYTHONUNBUFFERED: "1" + + # Secrets are created in db-secret.yaml + # These are passed via envFrom secretRef + + ingress: + enabled: true + className: "alb" + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' + alb.ingress.kubernetes.io/certificate-arn: "" # Set in project-specific values + hosts: + - host: api-my-recipes.dvirlabs.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: api-my-recipes-tls + hosts: + - api-my-recipes.dvirlabs.com + +# Frontend configuration +frontend: + name: frontend + replicaCount: 2 + image: + repository: harbor.dvirlabs.com/my-apps/my-recipes-frontend + pullPolicy: IfNotPresent + tag: "latest" + + service: + type: ClusterIP + port: 80 + targetPort: 80 + + env: + API_BASE: "https://api-my-recipes.dvirlabs.com" + + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + cpu: 200m + memory: 256Mi + + ingress: + enabled: true + className: "alb" + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' + alb.ingress.kubernetes.io/certificate-arn: "" # Set in project-specific values + hosts: + - host: my-recipes.dvirlabs.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: my-recipes-tls + hosts: + - my-recipes.dvirlabs.com + externalUrl: "https://my-recipes.dvirlabs.com" + +# PostgreSQL configuration +postgres: + name: db + image: + repository: postgres + tag: "16-alpine" + pullPolicy: IfNotPresent + + user: recipes_user + password: recipes_password + database: recipes_db + port: 5432 + + service: + type: ClusterIP + port: 5432 + targetPort: 5432 + + persistence: + enabled: true + accessMode: ReadWriteOnce + storageClass: "nfs-client" + size: 10Gi + + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 1000m + memory: 1Gi + +# OAuth Configuration +oauth: + google: + clientId: "143092846986-hsi59m0on2c9rb5qrdoejfceieao2ioc.apps.googleusercontent.com" + clientSecret: "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" + redirectUri: "https://api-my-recipes.dvirlabs.com/auth/google/callback" + + azure: + clientId: "db244cf5-eb11-4738-a2ea-5b0716c9ec0a" + clientSecret: "Zad8Q~qRBxaQq8up0lLXAq4pHzrVM2JFGFJhHaDp" + tenantId: "consumers" + redirectUri: "https://api-my-recipes.dvirlabs.com/auth/azure/callback" + +# Email Configuration +email: + smtpHost: "smtp.gmail.com" + smtpPort: "587" + smtpUser: "dvirlabs@gmail.com" + smtpPassword: "agaanrhbbazbdytv" + smtpFrom: "dvirlabs@gmail.com" + +# S3 Backup Configuration +s3: + endpoint: "https://s3.amazonaws.com" # Can be overridden for specific regions + accessKey: "" # Set this in project-specific values.yaml + secretKey: "" # Set this in project-specific values.yaml + bucketName: "" # Set this in project-specific values.yaml + region: "us-east-1" # Set this in project-specific values.yaml + backupInterval: "weekly" # Options: test (1 min), daily, weekly + +# Admin User Configuration +admin: + username: "admin" + email: "admin@example.com" + password: "admin123" # Change this in production! + firstName: "Admin" + lastName: "User" + displayName: "Admin User" + +# Ingress configuration +ingress: + enabled: false # Individual frontend/backend ingress resources handle routing instead + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + hosts: + - host: my-recipes.dvirlabs.com + paths: + - path: / + pathType: Prefix + backend: frontend + tls: + - secretName: recipes-tls + hosts: + - my-recipes.dvirlabs.com + diff --git a/aws/final-app/values.yaml b/aws/final-app/values.yaml new file mode 100644 index 0000000..e526c3d --- /dev/null +++ b/aws/final-app/values.yaml @@ -0,0 +1,110 @@ +# Project-specific values for AWS EKS deployment +# This file overrides the base values in my-recipes-chart/values.yaml + +global: + namespace: my-apps + +# Backend configuration +backend: + replicaCount: 2 + image: + repository: 430842105273.dkr.ecr.eu-central-1.amazonaws.com/my-recipes-backend # Update with your ECR repository + tag: "latest" + + ingress: + className: "alb" + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' + # Add your ACM certificate ARN below if you have one + # alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:..." + hosts: + - host: api-my-recipes.aws-dvirlabs.com + paths: + - path: / + pathType: Prefix + +# Frontend configuration +frontend: + replicaCount: 2 + image: + repository: 430842105273.dkr.ecr.eu-central-1.amazonaws.com/my-recipes-frontend # Update with your ECR repository + tag: "latest" + + env: + API_BASE: "https://api-my-recipes.aws-dvirlabs.com" + + ingress: + className: "alb" + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' + # Add your ACM certificate ARN below if you have one + # alb.ingress.kubernetes.io/certificate-arn: "arn:aws:acm:..." + hosts: + - host: my-recipes.aws-dvirlabs.com + paths: + - path: / + pathType: Prefix + + externalUrl: "https://my-recipes.aws-dvirlabs.com" + +# PostgreSQL configuration +postgres: + # For AWS RDS, set this to use external database + # Leave enabled: true to use in-cluster database + enabled: false # Set to false if using RDS + + # If using RDS, these values are ignored but kept for reference + persistence: + storageClass: "gp3" # EKS default storage class + size: 20Gi + +# OAuth Configuration +oauth: + google: + clientId: "143092846986-hsi59m0on2c9rb5qrdoejfceieao2ioc.apps.googleusercontent.com" + clientSecret: "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" + redirectUri: "https://api-my-recipes.aws-dvirlabs.com/auth/google/callback" + + azure: + clientId: "db244cf5-eb11-4738-a2ea-5b0716c9ec0a" + clientSecret: "Zad8Q~qRBxaQq8up0lLXAq4pHzrVM2JFGFJhHaDp" + tenantId: "consumers" + redirectUri: "https://api-my-recipes.aws-dvirlabs.com/auth/azure/callback" + +# Email Configuration +email: + smtpHost: "smtp.gmail.com" + smtpPort: "587" + smtpUser: "dvirlabs@gmail.com" + smtpPassword: "agaanrhbbazbdytv" + smtpFrom: "dvirlabs@gmail.com" + +# S3 Backup Configuration for AWS +s3: + endpoint: "https://s3.eu-central-1.amazonaws.com" # Update with your region + accessKey: "AKIAXXXXXXXXXXXXXXXX" # Replace with your AWS Access Key + secretKey: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # Replace with your AWS Secret Key + bucketName: "my-recipes-backups" # Update with your S3 bucket name + region: "eu-central-1" # Update with your region + backupInterval: "weekly" + +# Admin User Configuration +admin: + username: "admin" + email: "dvirlabs@gmail.com" + password: "AdminPassword123!" # Change this after first login! + firstName: "Dvir" + lastName: "Admin" + displayName: "Dvir Admin" + +# Database connection for AWS RDS (used when postgres.enabled: false) +database: + host: "my-recipes-rds.chw4omcguqv7.eu-central-1.rds.amazonaws.com" + port: "5432" + name: "recipes_db" + user: "recipes_user" + password: "recipes_password" # Store securely in AWS Secrets Manager in production