Update schema.sql
This commit is contained in:
parent
cf6c9e7bd7
commit
16938f42bf
14
aws/final-app/my-recipes-chart-aws/Chart.yaml
Normal file
14
aws/final-app/my-recipes-chart-aws/Chart.yaml
Normal file
@ -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
|
||||
|
||||
@ -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);
|
||||
@ -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
|
||||
@ -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)
|
||||
@ -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
|
||||
@ -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 }}
|
||||
@ -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
|
||||
|
||||
@ -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 }}
|
||||
@ -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;
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
23
aws/final-app/my-recipes-chart-aws/templates/db-secret.yaml
Normal file
23
aws/final-app/my-recipes-chart-aws/templates/db-secret.yaml
Normal file
@ -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 }}
|
||||
|
||||
39
aws/final-app/my-recipes-chart-aws/templates/db-service.yaml
Normal file
39
aws/final-app/my-recipes-chart-aws/templates/db-service.yaml
Normal file
@ -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 }}
|
||||
|
||||
@ -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 }}
|
||||
|
||||
@ -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 }}
|
||||
@ -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 }}
|
||||
89
aws/final-app/my-recipes-chart-aws/templates/ingress.yaml
Normal file
89
aws/final-app/my-recipes-chart-aws/templates/ingress.yaml
Normal file
@ -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 }}
|
||||
182
aws/final-app/my-recipes-chart-aws/values.yaml
Normal file
182
aws/final-app/my-recipes-chart-aws/values.yaml
Normal file
@ -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
|
||||
|
||||
110
aws/final-app/values.yaml
Normal file
110
aws/final-app/values.yaml
Normal file
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user