Compare commits

...

36 Commits

Author SHA1 Message Date
4a7532fb85 fix: use POSTGRES_PASSWORD from secret instead of hardcoded value
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m2s
2025-05-30 22:33:31 +02:00
9786b8da06 test: hardcode password to test connection
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m4s
2025-05-30 19:31:06 +02:00
633a4e95c2 fix: add password debugging to migration job
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
2025-05-30 19:28:27 +02:00
2bf8d04657 feat: add environment variable debugging to migration job
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m3s
2025-05-30 19:19:05 +02:00
5820150ec9 fix: update POSTGRES_NAME to POSTGRES_DB in values template
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
2025-05-30 19:14:28 +02:00
eb079fa9e4 fix: update database environment variable names to match PostgreSQL expectations
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
2025-05-30 19:11:04 +02:00
079018a77e fix: remove optional ENCRYPTION_KEY from migration job
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m7s
2025-05-30 18:15:19 +02:00
6f6ddb072b fix: use secrets for sensitive values in migration job
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m6s
2025-05-27 13:08:28 +02:00
7e132608d7 test: add detailed environment and connection testing
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m6s
2025-05-26 16:37:41 +02:00
03f615bf57 test: add detailed connection testing with connection string
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m15s
2025-05-26 16:18:04 +02:00
b2706bc747 test: add detailed connection testing to migration job
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m1s
2025-05-25 23:49:25 +02:00
5c3833a9e4 fix: correct shell script syntax in migration job init container
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m2s
2025-05-25 13:17:58 +02:00
e5d7a52e59 fix: improve PostgreSQL initialization and authentication - Add startup probe for PostgreSQL - Update authentication to use scram-sha-256 consistently - Add better logging for database operations - Improve migration job initialization checks
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m2s
2025-05-25 11:12:01 +02:00
55feccec4b hotfix
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m6s
2025-05-25 10:42:36 +02:00
fda611d249 updated database config
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m6s
2025-05-24 14:05:35 +02:00
fe6ceb5b39 chore: trigger clean pipeline after VPS reset
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m17s
2025-05-24 01:43:35 +02:00
2929e7b83f fix: set both POSTGRES_HOST and POSTGRES_HOSTNAME for backend env
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m15s
2025-05-24 01:15:59 +02:00
717b9978d5 chore: trigger clean pipeline run
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m5s
2025-05-24 00:56:49 +02:00
5e12a9cb25 fix: quote postgres env values for Helm rendering
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m8s
2025-05-24 00:46:28 +02:00
fa08e6de1b fix: add POSTGRES_HOSTNAME env to migration job
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m6s
2025-05-22 19:37:33 +02:00
addcc6d7e2 fix: update backend env to use POSTGRES_HOSTNAME instead of POSTGRES_HOST
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m12s
2025-05-22 19:27:10 +02:00
c8ddb9e732 fixed secrets
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m5s
2025-05-22 19:16:59 +02:00
45a2ba4611 fix: add imagePullSecrets to migration job
Some checks failed
Deploy to Production / Build and Deploy (push) Has been cancelled
2025-05-22 19:16:23 +02:00
576ce89698 docs: add section on Gitea secrets as source of truth for production
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m4s
2025-05-22 18:51:48 +02:00
f3bece7009 fix: add imagePullSecrets for private registry auth
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m6s
2025-05-22 18:26:03 +02:00
2b589a93b2 fix: add port values for backend and frontend in prod values template
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 6m8s
2025-05-22 14:54:24 +02:00
458bfb9af1 fix: set backend.image and frontend.image as strings for helm
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m7s
2025-05-22 14:46:21 +02:00
0c66dd65c5 ci: generate values.prod.yaml from template before deploy
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m9s
2025-05-22 14:41:29 +02:00
fdb61a21bf chore: add prod values template for dev and ci/cd
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m7s
2025-05-22 14:38:35 +02:00
5ef9cfdaa9 chore: remove unused .yml files for consistency
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m5s
2025-05-22 14:17:44 +02:00
893e36d8c9 docs: add CI/CD Kubernetes deployment setup instructions
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m13s
2025-05-22 14:11:08 +02:00
fef95ff9eb ci: install helm before deploy
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m14s
2025-05-22 14:03:46 +02:00
4499e11603 added frontend base api url
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m14s
2025-05-22 13:46:23 +02:00
c69cd4768c trigger pipeline
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m2s
2025-05-22 13:31:08 +02:00
e801a3b927 fixed reference
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 1m7s
2025-05-22 13:24:31 +02:00
e46cfeaa4b Merge pull request 'fixed path for implied backend, which sits on root actual' (#2) from hotfix-paths into main
Some checks failed
Deploy to Production / Build and Deploy (push) Failing after 3m10s
Reviewed-on: #2
2025-05-21 23:57:52 +00:00
14 changed files with 408 additions and 82 deletions

@ -31,10 +31,16 @@ jobs:
cache-from: type=registry,ref=registry.liquidrinu.com/fusero-backend:buildcache cache-from: type=registry,ref=registry.liquidrinu.com/fusero-backend:buildcache
cache-to: type=registry,ref=registry.liquidrinu.com/fusero-backend:buildcache,mode=max cache-to: type=registry,ref=registry.liquidrinu.com/fusero-backend:buildcache,mode=max
- name: Create .env file
run: |
echo "VITE_API_BASE_URL=/api" > ./frontend/.env
# This only affects the CI/CD build, not your local dev .env
- name: Build and Push Frontend - name: Build and Push Frontend
uses: docker/build-push-action@v4 uses: docker/build-push-action@v4
with: with:
context: ./frontend context: ./frontend
file: ./frontend/Dockerfile.dev
push: true push: true
tags: registry.liquidrinu.com/fusero-frontend:latest tags: registry.liquidrinu.com/fusero-frontend:latest
cache-from: type=registry,ref=registry.liquidrinu.com/fusero-frontend:buildcache cache-from: type=registry,ref=registry.liquidrinu.com/fusero-frontend:buildcache
@ -68,6 +74,13 @@ jobs:
run: | run: |
kubectl delete job fusero-backend-db-init -n fusero-prod || true kubectl delete job fusero-backend-db-init -n fusero-prod || true
- name: Install Helm
run: |
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
- name: Generate values.prod.yaml from template
run: cp chart/values.prod.template.yaml chart/values.prod.yaml
- name: Deploy to Kubernetes - name: Deploy to Kubernetes
run: | run: |
helm upgrade --install fusero ./chart \ helm upgrade --install fusero ./chart \
@ -75,8 +88,8 @@ jobs:
--create-namespace \ --create-namespace \
--values ./chart/values.prod.yaml \ --values ./chart/values.prod.yaml \
--values ./chart/secrets.prod.yaml \ --values ./chart/secrets.prod.yaml \
--set backend.image.repository=registry.liquidrinu.com/fusero-backend \ --set backend.image=registry.liquidrinu.com/fusero-backend:latest \
--set frontend.image.repository=registry.liquidrinu.com/fusero-frontend --set frontend.image=registry.liquidrinu.com/fusero-frontend:latest
- name: Wait for migration/seed job - name: Wait for migration/seed job
run: | run: |

4
.gitignore vendored

@ -143,3 +143,7 @@ chart/secrets.*.yaml
!chart/values.prod.public.yaml !chart/values.prod.public.yaml
.bkup/ .bkup/
# Ignore production values and secrets files
chart/values.prod.yaml
chart/secrets.prod.yaml

138
README.md

@ -10,44 +10,9 @@ A full-stack application boilerplate with a React frontend and Node.js backend
- [📚 Table of Contents](#-table-of-contents) - [📚 Table of Contents](#-table-of-contents)
- [📁 Project Structure](#-project-structure) - [📁 Project Structure](#-project-structure)
- [⚙️ Prerequisites](#-prerequisites) - [⚙️ Prerequisites](#-prerequisites)
- [💻 Development Setup](#-development-setup) - [Development Setup](#development-setup)
- [To create a new migration:](#to-create-a-new-migration) - [Important Note: Database Must Run in Docker](#important-note-database-must-run-in-docker)
- [npm run migration:create](#npm-run-migrationcreate)
- [To apply migrations:](#to-apply-migrations)
- [To seed the database:](#to-seed-the-database)
- [Alternate: Running Services in Separate Terminals](#alternate-running-services-in-separate-terminals)
- [🛠️ Environment Setup](#-environment-setup)
- [For Kubernetes, these are set in chart/values.yaml:](#for-kubernetes-these-are-set-in-chartvaluesyaml)
- [POSTGRES\_NAME=fusero-boilerplate-db](#postgres_namefusero-boilerplate-db)
- [POSTGRES\_HOSTNAME=postgres-service](#postgres_hostnamepostgres-service)
- [POSTGRES\_PORT=19095](#postgres_port19095)
- [POSTGRES\_USER=root](#postgres_userroot)
- [POSTGRES\_PASSWORD=root123](#postgres_passwordroot123)
- [🐳 Docker Development](#-docker-development)
- [To create a new migration:](#to-create-a-new-migration-1)
- [npm run migration:create](#npm-run-migrationcreate-1)
- [To apply migrations:](#to-apply-migrations-1)
- [To seed the database:](#to-seed-the-database-1)
- [🚀 Kubernetes Deployment](#-kubernetes-deployment)
- [🌐 Frontend Routing in Production](#-frontend-routing-in-production)
- [🔐 HTTPS with Self-Signed Certificates](#-https-with-self-signed-certificates)
- [🧠 Development Best Practices](#-development-best-practices)
- [📘 API Documentation](#-api-documentation)
- [🧩 ChatGPT-Powered Endpoint Creation](#-chatgpt-powered-endpoint-creation)
- [🧪 Troubleshooting](#-troubleshooting)
- [🤝 Contributing](#-contributing)
- [📄 License](#-license)
- [Kubernetes Troubleshooting \& Redeployment Commands](#kubernetes-troubleshooting--redeployment-commands)
- [1. Rebuild the backend Docker image (after code/config changes)](#1-rebuild-the-backend-docker-image-after-codeconfig-changes)
- [2. (If using a remote registry) Push the image](#2-if-using-a-remote-registry-push-the-image) - [2. (If using a remote registry) Push the image](#2-if-using-a-remote-registry-push-the-image)
- [3. Upgrade the Helm release with the latest values](#3-upgrade-the-helm-release-with-the-latest-values)
- [4. Restart the backend deployment to pick up new images and env vars](#4-restart-the-backend-deployment-to-pick-up-new-images-and-env-vars)
- [5. Check backend pod environment variables](#5-check-backend-pod-environment-variables)
- [6. Check backend pod logs for errors](#6-check-backend-pod-logs-for-errors)
- [7. If you change DB env vars or code, repeat steps 1-6](#7-if-you-change-db-env-vars-or-code-repeat-steps-1-6)
- [Frontend Rebuild \& Redeploy (Kubernetes)](#frontend-rebuild--redeploy-kubernetes)
- [1. Rebuild the frontend Docker image](#1-rebuild-the-frontend-docker-image)
- [2. (If using a remote registry) Push the image](#2-if-using-a-remote-registry-push-the-image-1)
- [3. Upgrade the Helm release](#3-upgrade-the-helm-release) - [3. Upgrade the Helm release](#3-upgrade-the-helm-release)
- [4. Restart the frontend deployment](#4-restart-the-frontend-deployment) - [4. Restart the frontend deployment](#4-restart-the-frontend-deployment)
- [Port-Forwarding for Local Access](#port-forwarding-for-local-access) - [Port-Forwarding for Local Access](#port-forwarding-for-local-access)
@ -82,12 +47,17 @@ A full-stack application boilerplate with a React frontend and Node.js backend
- [Troubleshooting Production](#troubleshooting-production) - [Troubleshooting Production](#troubleshooting-production)
- [🆕 Recent Improvements \& Troubleshooting](#-recent-improvements--troubleshooting) - [🆕 Recent Improvements \& Troubleshooting](#-recent-improvements--troubleshooting)
- [🚀 Production Deployment Pipeline (CI/CD)](#-production-deployment-pipeline-cicd) - [🚀 Production Deployment Pipeline (CI/CD)](#-production-deployment-pipeline-cicd)
- [CI/CD Kubernetes Deployment Setup](#cicd-kubernetes-deployment-setup)
- [Using Private Docker Registry with Kubernetes](#using-private-docker-registry-with-kubernetes)
- [Production Secrets Management (Gitea as Source of Truth)](#production-secrets-management-gitea-as-source-of-truth)
- [CI/CD Pipeline Behavior: Multiple Merges to Main](#cicd-pipeline-behavior-multiple-merges-to-main)
--- ---
## 📁 Project Structure ## 📁 Project Structure
fusero-app-boilerplate/ ```
fusero-app-boilerplate
├── chart/ # Helm chart for Kubernetes ├── chart/ # Helm chart for Kubernetes
│ ├── Chart.yaml │ ├── Chart.yaml
│ ├── values.dev.yaml │ ├── values.dev.yaml
@ -125,6 +95,7 @@ fusero-app-boilerplate/
├── test/ ├── test/
├── utils/ ├── utils/
└── README.md └── README.md
```
--- ---
@ -557,3 +528,94 @@ The application uses a secure secrets management approach:
- This ensures your database is always migrated and seeded with every deploy, and you'll know immediately if something goes wrong. - This ensures your database is always migrated and seeded with every deploy, and you'll know immediately if something goes wrong.
- To trigger a production deployment, just push or merge to `main`. - To trigger a production deployment, just push or merge to `main`.
## CI/CD Kubernetes Deployment Setup
To enable automated deployment to your Kubernetes cluster from CI/CD (Gitea Actions):
1. **Get your kubeconfig file from your Kubernetes master node or provider.**
- For self-hosted clusters, it's usually at `~/.kube/config` on the master node.
- For managed clusters, download it from your provider's dashboard.
2. **Edit the kubeconfig file:**
- Change the `server:` field to use your cluster's public IP or DNS, e.g.:
```yaml
server: https://[YOUR_PUBLIC_IP_OR_DNS]:6443
```
(For IPv6, use square brackets around the address.)
3. **Base64-encode the kubeconfig file as a single line:**
- On Linux:
```bash
base64 -w 0 /path/to/your/kubeconfig
```
- On Mac:
```bash
base64 /path/to/your/kubeconfig | tr -d '\n'
```
4. **Add the base64 string as a secret in your Gitea repository:**
- Go to **Settings → Secrets**
- Name: `KUBE_CONFIG`
- Value: (paste the base64 string)
5. **Make sure port 6443 is open to your CI/CD runner's IP in your VPS firewall/security group.**
6. **Your pipeline will now be able to deploy to your Kubernetes cluster.**
---
## Using Private Docker Registry with Kubernetes
If you use a private Docker registry (like registry.liquidrinu.com), you must create a Kubernetes secret and reference it in your deployments:
1. **Create the registry secret:**
```bash
kubectl create secret docker-registry regcred \
--docker-server=registry.liquidrinu.com \
--docker-username=YOUR_REGISTRY_USERNAME \
--docker-password=YOUR_REGISTRY_PASSWORD \
--docker-email=YOUR_EMAIL \
-n fusero-prod
```
2. **Reference the secret in your deployment YAMLs:**
In your deployment spec, add:
```yaml
imagePullSecrets:
- name: regcred
```
Example:
```yaml
spec:
template:
spec:
imagePullSecrets:
- name: regcred
containers:
- name: backend
image: ...
```
This allows Kubernetes to authenticate to your private registry and pull images securely.
---
## Production Secrets Management (Gitea as Source of Truth)
- In production, all sensitive values (like `POSTGRES_PASSWORD`, `DEFAULT_ADMIN_PASSWORD`, etc.) are managed as secrets in your Gitea repository (Settings → Secrets).
- The CI/CD pipeline uses these secrets to generate `chart/secrets.prod.yaml` and other files at runtime.
- Helm uses these generated files to set environment variables for your Kubernetes resources.
- The Postgres password is set from the secret **only when the database is first initialized** (i.e., when the persistent volume is empty). Changing the secret later will not update the password for an existing database unless you reset the DB or delete the volume.
- **Summary:** Gitea secrets are the source of truth for production. Always update secrets in Gitea and redeploy to apply changes to new pods.
---
## CI/CD Pipeline Behavior: Multiple Merges to Main
- If multiple merges or pushes happen to the `main` branch in quick succession, your CI/CD system will start a separate pipeline for each commit.
- These pipelines will run in parallel unless your CI/CD is configured to queue or cancel previous runs.
- This can result in race conditions, where the last pipeline to finish will determine the final deployed state.
- **Best practice:** Avoid merging multiple large changes to `main` at the same time. Wait for the pipeline to finish before merging the next PR, or configure your CI/CD to cancel previous runs on new pushes.
---

@ -1,6 +0,0 @@
apiVersion: v2
name: fusero
description: Fusero App Boilerplate Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"

@ -12,6 +12,8 @@ spec:
labels: labels:
app: fusero-backend app: fusero-backend
spec: spec:
imagePullSecrets:
- name: regcred
containers: containers:
- name: backend - name: backend
image: {{ .Values.backend.image }} image: {{ .Values.backend.image }}

@ -8,18 +8,62 @@ spec:
metadata: metadata:
name: fusero-backend-db-init name: fusero-backend-db-init
spec: spec:
imagePullSecrets:
- name: regcred
containers: containers:
- name: migrate-seed - name: migrate-seed
image: {{ .Values.backend.image }} image: {{ .Values.backend.image }}
command: ["/bin/sh", "-c"] command: ["/bin/sh", "-c"]
args: args:
- | - |
echo "Running migrations and seeds..." && \ echo "=== Environment Variables ==="
npx mikro-orm migration:up && \ env | grep -i postgres
echo "=== Testing Connection ==="
PGPASSWORD=$POSTGRES_PASSWORD psql "postgresql://$POSTGRES_USER@$POSTGRES_HOSTNAME:$POSTGRES_PORT/$POSTGRES_NAME" -c "SELECT 1"
echo "=== Running Migrations ==="
npx mikro-orm migration:up
echo "=== Running Seeds ==="
npm run seed npm run seed
env: env:
{{- range $key, $val := .Values.backend.env }} - name: POSTGRES_HOSTNAME
- name: {{ $key }} value: "postgres-service"
value: "{{ $val }}" - name: POSTGRES_PORT
{{- end }} value: "5432"
- name: POSTGRES_NAME
value: "fusero-db"
- name: POSTGRES_USER
value: "prod_admin"
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: fusero-backend-secrets
key: POSTGRES_PASSWORD
- name: NODE_ENV
value: "production"
- name: DEFAULT_ADMIN_USERNAME
value: "{{ .Values.backend.env.DEFAULT_ADMIN_USERNAME }}"
- name: DEFAULT_ADMIN_EMAIL
value: "{{ .Values.backend.env.DEFAULT_ADMIN_EMAIL }}"
- name: DEFAULT_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: fusero-backend-secrets
key: DEFAULT_ADMIN_PASSWORD
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: fusero-backend-secrets
key: JWT_SECRET
- name: CHATGPT_API_KEY
valueFrom:
secretKeyRef:
name: fusero-backend-secrets
key: CHATGPT_API_KEY
- name: CANVAS_API_KEY
valueFrom:
secretKeyRef:
name: fusero-backend-secrets
key: CANVAS_API_KEY
- name: CANVAS_API_URL
value: "{{ .Values.backend.env.CANVAS_API_URL }}"
restartPolicy: Never restartPolicy: Never

@ -12,6 +12,8 @@ spec:
labels: labels:
app: fusero-frontend app: fusero-frontend
spec: spec:
imagePullSecrets:
- name: regcred
containers: containers:
- name: frontend - name: frontend
image: {{ .Values.frontend.image }} image: {{ .Values.frontend.image }}

@ -8,11 +8,51 @@ data:
local all all trust local all all trust
host all all 127.0.0.1/32 trust host all all 127.0.0.1/32 trust
host all all ::1/128 trust host all all ::1/128 trust
host all all 0.0.0.0/0 md5 host all all 0.0.0.0/0 scram-sha-256
postgresql.conf: | postgresql.conf: |
# Connection Settings
listen_addresses = '*' listen_addresses = '*'
max_connections = 100 max_connections = 100
# Memory Settings
shared_buffers = 128MB shared_buffers = 128MB
dynamic_shared_memory_type = posix work_mem = 4MB
maintenance_work_mem = 64MB
# Write Ahead Log
max_wal_size = 1GB max_wal_size = 1GB
min_wal_size = 80MB min_wal_size = 80MB
checkpoint_timeout = 5min
checkpoint_completion_target = 0.9
# Query Planner
random_page_cost = 1.1
effective_cache_size = 4GB
# Autovacuum
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 1min
autovacuum_vacuum_threshold = 50
autovacuum_analyze_threshold = 50
# Logging
log_min_duration_statement = 1000
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 0
log_autovacuum_min_duration = 0
# Other Settings
dynamic_shared_memory_type = posix
effective_io_concurrency = 200
default_statistics_target = 100
# Authentication
password_encryption = scram-sha-256
# Error Reporting
log_min_error_statement = error
log_statement = 'all'

@ -19,11 +19,42 @@ spec:
- containerPort: 5432 - containerPort: 5432
env: env:
- name: POSTGRES_DB - name: POSTGRES_DB
value: {{ .Values.postgres.dbName }} value: "{{ .Values.postgres.dbName }}"
- name: POSTGRES_USER - name: POSTGRES_USER
value: {{ .Values.postgres.user }} value: "{{ .Values.postgres.user }}"
- name: POSTGRES_PASSWORD - name: POSTGRES_PASSWORD
value: {{ .Values.postgres.password }} value: "{{ .Values.postgres.password }}"
- name: POSTGRES_HOST_AUTH_METHOD
value: "scram-sha-256"
startupProbe:
exec:
command:
- pg_isready
- -U
- "{{ .Values.postgres.user }}"
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 30
readinessProbe:
exec:
command:
- pg_isready
- -U
- "{{ .Values.postgres.user }}"
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 5
livenessProbe:
exec:
command:
- pg_isready
- -U
- "{{ .Values.postgres.user }}"
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
volumeMounts: volumeMounts:
- mountPath: /var/lib/postgresql/data - mountPath: /var/lib/postgresql/data
name: postgres-data name: postgres-data

@ -0,0 +1,69 @@
global:
namespace: fusero-prod
security:
cors:
origin: "https://your-domain.com"
methods: "GET,POST,PUT,DELETE"
credentials: true
https:
enabled: true
certSecret: "your-tls-secret"
logging:
level: "info"
format: "json"
monitoring:
prometheus:
enabled: true
path: "/metrics"
backend:
image: registry.liquidrinu.com/fusero-backend:latest
port: 14000
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
env:
POSTGRES_HOSTNAME: postgres-service
POSTGRES_PORT: "5432"
POSTGRES_DB: fusero-db
POSTGRES_USER: prod_admin
POSTGRES_PASSWORD: "<POSTGRES_PASSWORD>"
DEFAULT_ADMIN_USERNAME: admin
DEFAULT_ADMIN_EMAIL: admin@your-domain.com
DEFAULT_ADMIN_PASSWORD: "<DEFAULT_ADMIN_PASSWORD>"
ENCRYPTION_KEY: "<ENCRYPTION_KEY>"
JWT_SECRET: "<JWT_SECRET>"
CHATGPT_API_KEY: "<CHATGPT_API_KEY>"
CANVAS_API_KEY: "<CANVAS_API_KEY>"
CANVAS_API_URL: https://your-canvas-instance/api/v1
frontend:
image: registry.liquidrinu.com/fusero-frontend:latest
port: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "300m"
memory: "256Mi"
env:
VITE_API_BASE_URL: https://your-domain.com
postgres:
image: postgres:15
storage: 5Gi
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
password: "<POSTGRES_PASSWORD>"
user: "prod_admin"
dbName: "fusero-db"

70
chart/values.prod.yaml Normal file

@ -0,0 +1,70 @@
global:
namespace: fusero-prod
security:
cors:
origin: "https://your-domain.com"
methods: "GET,POST,PUT,DELETE"
credentials: true
https:
enabled: true
certSecret: "your-tls-secret"
logging:
level: "info"
format: "json"
monitoring:
prometheus:
enabled: true
path: "/metrics"
backend:
image: registry.liquidrinu.com/fusero-backend:latest
port: 14000
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
env:
POSTGRES_HOST: postgres-service
POSTGRES_HOSTNAME: postgres-service
POSTGRES_PORT: "5432"
POSTGRES_NAME: fusero-db
POSTGRES_USER: prod_admin
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
DEFAULT_ADMIN_USERNAME: admin
DEFAULT_ADMIN_EMAIL: admin@fusero.nl
DEFAULT_ADMIN_PASSWORD: ${DEFAULT_ADMIN_PASSWORD}
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
JWT_SECRET: ${JWT_SECRET}
CHATGPT_API_KEY: ${CHATGPT_API_KEY}
CANVAS_API_KEY: ${CANVAS_API_KEY}
CANVAS_API_URL: https://talnet.instructure.com/api/v1
frontend:
image: registry.liquidrinu.com/fusero-frontend:latest
port: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "300m"
memory: "256Mi"
env:
VITE_API_BASE_URL: https://app.fusero.nl
postgres:
image: postgres:15
storage: 5Gi
dbName: fusero-db
user: prod_admin
password: ${POSTGRES_PASSWORD}
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"

@ -1,22 +0,0 @@
backend:
image: fusero-backend:latest
env:
POSTGRES_HOST: postgres-service
POSTGRES_PORT: "5432"
POSTGRES_NAME: fusero-db
POSTGRES_USER: prod_admin
POSTGRES_PASSWORD: REPLACE_ME
DEFAULT_ADMIN_USERNAME: admin
DEFAULT_ADMIN_EMAIL: admin@fusero.nl
DEFAULT_ADMIN_PASSWORD: STRONG_REPLACE_ME
ENCRYPTION_KEY: PROD_REPLACE_ME_KEY
JWT_SECRET: PROD_REPLACE_ME_JWT
CHATGPT_API_KEY: PROD_REPLACE_ME_CHATGPT
CANVAS_API_KEY: PROD_REPLACE_ME_CANVAS
frontend:
image: fusero-frontend:latest
postgres:
image: postgres:15
storage: 5Gi

@ -3,12 +3,21 @@ import { PostgreSqlDriver } from '@mikro-orm/postgresql';
import { Migrator } from '@mikro-orm/migrations'; import { Migrator } from '@mikro-orm/migrations';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
// Load environment variables if not in Kubernetes
if (process.env.KUBERNETES_SERVICE_HOST === undefined) { if (process.env.KUBERNETES_SERVICE_HOST === undefined) {
dotenv.config({ override: true }); dotenv.config({ override: true });
} }
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === 'production';
// Validate required environment variables
const requiredEnvVars = ['POSTGRES_DB', 'POSTGRES_USER', 'POSTGRES_PASSWORD'];
const missingEnvVars = requiredEnvVars.filter(envVar => !process.env[envVar]);
if (missingEnvVars.length > 0 && isProduction) {
throw new Error(`Missing required environment variables: ${missingEnvVars.join(', ')}`);
}
const config: Options = { const config: Options = {
driver: PostgreSqlDriver, driver: PostgreSqlDriver,
entities: [ entities: [
@ -25,14 +34,14 @@ const config: Options = {
warnWhenNoEntities: true, warnWhenNoEntities: true,
disableDynamicFileAccess: false, disableDynamicFileAccess: false,
}, },
dbName: process.env.POSTGRES_NAME || 'fusero-boilerplate-db', dbName: process.env.POSTGRES_DB || 'fusero-boilerplate-db',
host: process.env.POSTGRES_HOSTNAME || 'localhost', host: process.env.POSTGRES_HOSTNAME || 'localhost',
port: Number(process.env.POSTGRES_PORT) || 5432, port: Number(process.env.POSTGRES_PORT) || 5432,
user: process.env.POSTGRES_USER || 'root', user: process.env.POSTGRES_USER || 'root',
password: process.env.POSTGRES_PASSWORD || 'root123', password: process.env.POSTGRES_PASSWORD || 'root123',
debug: !isProduction, debug: !isProduction,
migrations: { migrations: {
tableName: process.env.POSTGRES_NAME, tableName: process.env.POSTGRES_DB,
path: isProduction ? './dist/src/database/migrations' : './src/database/migrations', path: isProduction ? './dist/src/database/migrations' : './src/database/migrations',
glob: '!(*.d).{js,ts}', glob: '!(*.d).{js,ts}',
transactional: true, transactional: true,
@ -43,6 +52,13 @@ const config: Options = {
snapshot: true, snapshot: true,
emit: 'ts', emit: 'ts',
}, },
// Add connection pool settings
pool: {
min: 2,
max: 10,
idleTimeoutMillis: 30000,
acquireTimeoutMillis: 30000,
},
}; };
export default config; export default config;

1
trigger.txt Normal file

@ -0,0 +1 @@
# trigger