Save current state before cleaning history

This commit is contained in:
liquidrinu 2025-05-21 09:27:45 +02:00
parent 7f463ee287
commit 0167ffdd18
19 changed files with 565 additions and 50 deletions

@ -1,12 +1,83 @@
image: lachlanevenson/k8s-helm:latest version: 1.0
stages: workflow:
- deploy name: Deploy to Production
on:
push:
branches:
- main
variables: jobs:
KUBECONFIG: /root/.kube/config # Adjust if you're mounting a kubeconfig differently build-and-deploy:
name: Build and Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
deploy: - name: Set up Docker Buildx
stage: deploy uses: docker/setup-buildx-action@v2
script:
- helm upgrade --install fusero ./chart -f ./chart/values-prod.yaml - name: Login to Docker Registry
uses: docker/login-action@v2
with:
registry: registry.liquidrinu.com
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and Push Backend
uses: docker/build-push-action@v4
with:
context: ./backend
push: true
tags: registry.liquidrinu.com/fusero-backend:latest
cache-from: type=registry,ref=registry.liquidrinu.com/fusero-backend:buildcache
cache-to: type=registry,ref=registry.liquidrinu.com/fusero-backend:buildcache,mode=max
- name: Build and Push Frontend
uses: docker/build-push-action@v4
with:
context: ./frontend
push: true
tags: registry.liquidrinu.com/fusero-frontend:latest
cache-from: type=registry,ref=registry.liquidrinu.com/fusero-frontend:buildcache
cache-to: type=registry,ref=registry.liquidrinu.com/fusero-frontend:buildcache,mode=max
- name: Install kubectl
uses: azure/setup-kubectl@v3
with:
version: "latest"
- name: Setup kubeconfig
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > $HOME/.kube/config
chmod 600 $HOME/.kube/config
- name: Create secrets file
run: |
cat > ./chart/secrets.prod.yml << EOF
backend:
env:
POSTGRES_PASSWORD: "${{ secrets.POSTGRES_PASSWORD }}"
DEFAULT_ADMIN_PASSWORD: "${{ secrets.DEFAULT_ADMIN_PASSWORD }}"
ENCRYPTION_KEY: "${{ secrets.ENCRYPTION_KEY }}"
JWT_SECRET: "${{ secrets.JWT_SECRET }}"
CHATGPT_API_KEY: "${{ secrets.CHATGPT_API_KEY }}"
CANVAS_API_KEY: "${{ secrets.CANVAS_API_KEY }}"
EOF
- name: Deploy to Kubernetes
run: |
helm upgrade --install fusero ./chart \
--namespace fusero-prod \
--create-namespace \
--values ./chart/values.prod.yml \
--values ./chart/secrets.prod.yml \
--set backend.image.repository=registry.liquidrinu.com/fusero-backend \
--set frontend.image.repository=registry.liquidrinu.com/fusero-frontend
- name: Verify Deployment
run: |
kubectl rollout status deployment/fusero-backend -n fusero-prod
kubectl rollout status deployment/fusero-frontend -n fusero-prod

18
.gitignore vendored

@ -124,3 +124,21 @@ secrets.yml
values.dev.* values.dev.*
values.prod.* values.prod.*
# Secrets
chart/secrets.prod.yml
chart/secrets.*.yml
*.env
.env.*
# Development values with secrets
chart/values.dev.yml
# Production secrets
chart/secrets.prod.yml
chart/secrets.*.yml
# Keep templates and public configs
!chart/secrets.prod.template.yml
!chart/values.prod.template.yml
!chart/values.prod.public.yml

315
README.md

@ -11,15 +11,24 @@ A full-stack application boilerplate with a React frontend and Node.js backend
- [📁 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)
- [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) - [Alternate: Running Services in Separate Terminals](#alternate-running-services-in-separate-terminals)
- [🛠️ Environment Setup](#-environment-setup) - [🛠️ Environment Setup](#-environment-setup)
- [For Kubernetes, these are set in chart/values.yaml:](#for-kubernetes-these-are-set-in-chartvaluesyaml) - [For Kubernetes, these are set in chart/values.yml:](#for-kubernetes-these-are-set-in-chartvaluesyml)
- [POSTGRES\_NAME=fusero-boilerplate-db](#postgres_namefusero-boilerplate-db) - [POSTGRES\_NAME=fusero-boilerplate-db](#postgres_namefusero-boilerplate-db)
- [POSTGRES\_HOSTNAME=postgres-service](#postgres_hostnamepostgres-service) - [POSTGRES\_HOSTNAME=postgres-service](#postgres_hostnamepostgres-service)
- [POSTGRES\_PORT=19095](#postgres_port19095) - [POSTGRES\_PORT=19095](#postgres_port19095)
- [POSTGRES\_USER=root](#postgres_userroot) - [POSTGRES\_USER=root](#postgres_userroot)
- [POSTGRES\_PASSWORD=root123](#postgres_passwordroot123) - [POSTGRES\_PASSWORD=root123](#postgres_passwordroot123)
- [🚀 Production Deployment](#-production-deployment) - [🐳 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) - [🌐 Frontend Routing in Production](#-frontend-routing-in-production)
- [🔐 HTTPS with Self-Signed Certificates](#-https-with-self-signed-certificates) - [🔐 HTTPS with Self-Signed Certificates](#-https-with-self-signed-certificates)
- [🧠 Development Best Practices](#-development-best-practices) - [🧠 Development Best Practices](#-development-best-practices)
@ -53,17 +62,66 @@ A full-stack application boilerplate with a React frontend and Node.js backend
- [Debugging Frontend Pod Crashes: NGINX SSL Certificate Errors](#debugging-frontend-pod-crashes-nginx-ssl-certificate-errors) - [Debugging Frontend Pod Crashes: NGINX SSL Certificate Errors](#debugging-frontend-pod-crashes-nginx-ssl-certificate-errors)
- [How to fix for Kubernetes (Recommended)](#how-to-fix-for-kubernetes-recommended) - [How to fix for Kubernetes (Recommended)](#how-to-fix-for-kubernetes-recommended)
- [Connecting to the Database from Your Host (DBeaver, etc.)](#connecting-to-the-database-from-your-host-dbeaver-etc) - [Connecting to the Database from Your Host (DBeaver, etc.)](#connecting-to-the-database-from-your-host-dbeaver-etc)
- [🎯 Kubernetes Namespace Management](#-kubernetes-namespace-management)
- [Development Namespace Setup](#development-namespace-setup)
- [Production Namespace Setup](#production-namespace-setup)
- [Namespace Management Commands](#namespace-management-commands)
- [Recommended Kubernetes GUI Tools](#recommended-kubernetes-gui-tools)
- [🆕 Namespaced Development Environment with Helm](#-namespaced-development-environment-with-helm)
- [What was changed:](#what-was-changed)
- [How to use:](#how-to-use)
- [Why use namespaces?](#why-use-namespaces)
- [🔒 Production Security \& Best Practices](#-production-security--best-practices)
- [Environment Variables \& Secrets](#environment-variables--secrets)
- [HTTPS \& Certificates](#https--certificates)
- [CORS \& Security Headers](#cors--security-headers)
- [Logging \& Monitoring](#logging--monitoring)
- [Database Backup](#database-backup)
- [CI/CD \& Automated Testing](#cicd--automated-testing)
- [Troubleshooting Production](#troubleshooting-production)
--- ---
## 📁 Project Structure ## 📁 Project Structure
fusero-app-boilerplate/ fusero-app-boilerplate/
├── frontend/ # React frontend application ├── chart/ # Helm chart for Kubernetes
├── backend/ # Node.js backend application │ ├── Chart.yaml
├── docker-compose.yml # Production Docker configuration │ ├── values.dev.yaml
├── docker-compose.dev.yml # Development Docker configuration │ ├── values.prod.yml
└── chart/ # Helm chart for Kubernetes deployment │ └── templates/
├── config/
├── coverage/
├── dist/
├── docs/
├── frontend/ # React frontend app
│ ├── public/
│ └── src/
├── mikro-orm.config.ts
├── nginx/
├── node_modules/
├── package.json
├── package-lock.json
├── docker-compose.yml
├── docker-compose.dev.yml
├── .gitignore
├── .gitea-ci.yml
├── .prettierrc.json
├── .eslintrc.json
├── architecture.excalidraw
├── src/ # Node.js backend source
│ ├── apps/
│ ├── constants/
│ ├── database/
│ ├── middleware/
│ ├── plugins/
│ ├── shared/
│ ├── tests/
│ ├── types/
│ └── ...
├── test/
├── utils/
└── README.md
--- ---
@ -81,14 +139,18 @@ fusero-app-boilerplate/
🗃️ PostgreSQL must run in Docker for consistent behavior. 🗃️ PostgreSQL must run in Docker for consistent behavior.
Create volume and start the database: Create volume and start the database:
docker volume create fusero-db-data docker volume create fusero-dev-db-data
docker-compose up -d db docker-compose up -d db
Backend setup: Backend setup:
cd backend cd backend
cp .env.example .env cp .env.example .env
npm install npm install
# To create a new migration:
# npm run migration:create
# To apply migrations:
npm run migrate npm run migrate
# To seed the database:
npm run seed npm run seed
npm run dev & npm run dev &
cd .. cd ..
@ -130,7 +192,7 @@ POSTGRES_USER=root
POSTGRES_PASSWORD=root123 POSTGRES_PASSWORD=root123
JWT_SECRET=your_jwt_secret_key_here JWT_SECRET=your_jwt_secret_key_here
# For Kubernetes, these are set in chart/values.yaml: # For Kubernetes, these are set in chart/values.yml:
# POSTGRES_NAME=fusero-boilerplate-db # POSTGRES_NAME=fusero-boilerplate-db
# POSTGRES_HOSTNAME=postgres-service # POSTGRES_HOSTNAME=postgres-service
# POSTGRES_PORT=19095 # POSTGRES_PORT=19095
@ -142,13 +204,47 @@ VITE_API_BASE_URL=http://localhost:14000/api/v1
--- ---
## 🚀 Production Deployment ## 🐳 Docker Development
🗃️ PostgreSQL must run in Docker for consistent behavior.
Create volume and start the database:
docker volume create fusero-dev-db-data
docker-compose up -d db
Backend setup:
cd backend
cp .env.example .env
npm install
# To create a new migration:
# npm run migration:create
# To apply migrations:
npm run migrate
# To seed the database:
npm run seed
npm run dev &
cd ..
Frontend setup:
cd frontend
cp .env.example .env
npm install
npm run dev &
cd ..
App is running:
Frontend → http://localhost:3000
Backend → http://localhost:14000
---
## 🚀 Kubernetes Deployment
1. Build and run with Docker: 1. Build and run with Docker:
docker-compose up --build docker-compose up --build
2. Apply migrations and seed inside backend container: 2. Apply migrations and seed inside backend container:
docker exec -it fusero-app-backend npx mikro-orm migration:up docker exec -it fusero-app-backend npm run migrate
docker exec -it fusero-app-backend npm run seed docker exec -it fusero-app-backend npm run seed
3. Ensure all required environment variables are configured. 3. Ensure all required environment variables are configured.
@ -288,7 +384,7 @@ docker push <your-registry>/fusero-backend-dev:local
### 3. Upgrade the Helm release with the latest values ### 3. Upgrade the Helm release with the latest values
```bash ```bash
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
``` ```
### 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
@ -334,7 +430,7 @@ docker push <your-registry>/fusero-frontend-dev:local
### 3. Upgrade the Helm release ### 3. Upgrade the Helm release
```bash ```bash
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
``` ```
### 4. Restart the frontend deployment ### 4. Restart the frontend deployment
@ -386,7 +482,7 @@ Then rebuild and redeploy the frontend:
```bash ```bash
docker build -t fusero-frontend-dev:local ./frontend docker build -t fusero-frontend-dev:local ./frontend
# (push if needed) # (push if needed)
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
kubectl rollout restart deployment/fusero-frontend -n fusero kubectl rollout restart deployment/fusero-frontend -n fusero
``` ```
@ -450,7 +546,7 @@ This means NGINX is trying to load an SSL certificate that does not exist in the
3. (If using a remote registry) Push the image. 3. (If using a remote registry) Push the image.
4. Redeploy with Helm: 4. Redeploy with Helm:
```bash ```bash
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml helm upgrade fusero ./chart -n fusero -f chart/values.dev.yml
``` ```
5. Check pod status: 5. Check pod status:
```bash ```bash
@ -484,3 +580,190 @@ To connect to the Postgres database running in Kubernetes from your local machin
4. **Test the connection.** 4. **Test the connection.**
--- ---
## 🎯 Kubernetes Namespace Management
### Development Namespace Setup
```bash
# Create development namespace
kubectl create namespace fusero-dev
# Set current context to development namespace
kubectl config set-context --current --namespace=fusero-dev
# Deploy to development namespace
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yml
```
### Production Namespace Setup
```bash
# Create production namespace
kubectl create namespace fusero-prod
# Set current context to production namespace
kubectl config set-context --current --namespace=fusero-prod
# Deploy to production namespace
helm upgrade --install fusero ./chart -n fusero-prod -f chart/values.prod.yml
```
### Namespace Management Commands
```bash
# List all namespaces
kubectl get namespaces
# Switch between namespaces
kubectl config set-context --current --namespace=<namespace-name>
# View resources in current namespace
kubectl get all
# Delete namespace (be careful!)
kubectl delete namespace <namespace-name>
```
### Recommended Kubernetes GUI Tools
1. **Lens** - The most popular Kubernetes IDE
- Download: https://k8slens.dev/
- Features:
- Real-time cluster monitoring
- Multi-cluster management
- Namespace isolation
- Resource visualization
- Log streaming
- Terminal access
2. **K9s** - Terminal-based UI
- Install: `brew install k9s` (Mac) or `scoop install k9s` (Windows)
- Features:
- Fast navigation
- Resource management
- Log viewing
- Port forwarding
3. **Octant** - Web-based UI
- Install: https://octant.dev/
- Features:
- Resource visualization
- Configuration management
- Log viewing
- Port forwarding
---
## 🆕 Namespaced Development Environment with Helm
You have configured your Kubernetes development environment to use a dedicated namespace (`fusero-dev`) for all core services (backend, frontend, and database). This ensures resource isolation and easier management between development and production.
### What was changed:
- All Kubernetes service templates (`backend-service.yml`, `frontend-service.yml`, `postgres-service.yml`) now use a namespace variable.
- The development values file (`chart/values.dev.yml`) sets `global.namespace: fusero-dev` and updates all internal service hostnames to use this namespace.
- Helm deployments now target the `fusero-dev` namespace for all dev resources.
### How to use:
1. **Create the development namespace (if not already created):**
```bash
kubectl create namespace fusero-dev
```
2. **Deploy all services to the namespace:**
```bash
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yml
```
3. **Check running pods and services:**
```bash
kubectl get all -n fusero-dev
```
4. **If you update environment variables or service hostnames, repeat the Helm upgrade command.**
5. **If you see errors about immutable fields (e.g., for Jobs), delete the old Job before redeploying:**
```bash
kubectl delete job <job-name> -n fusero-dev
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yml
```
### Why use namespaces?
- Keeps dev and prod resources isolated
- Makes it easy to clean up or redeploy all dev resources
- Prevents accidental cross-environment access
---
## 🔒 Production Security & Best Practices
### Environment Variables & Secrets
The application uses a secure secrets management approach:
1. **Development Environment**:
- Use `.env` files locally (gitignored)
- Copy from `.env.example` as template
2. **Production Environment**:
- Secrets are managed through Gitea CI/CD secrets
- Template file: `chart/secrets.prod.template.yml`
- Actual secrets are generated during deployment
- Never commit actual secrets to the repository
3. **Required Secrets**:
- Database credentials
- Admin user credentials
- Security keys (encryption, JWT)
- API keys (ChatGPT, Canvas)
4. **Secrets in CI/CD**:
- Secrets are stored in Gitea CI/CD settings
- Automatically injected during deployment
- Used to generate `secrets.prod.yml` at runtime
5. **Security Best Practices**:
- All secrets files are gitignored
- Template files contain placeholder values
- Production secrets are never stored in the repository
- Regular rotation of secrets recommended
### HTTPS & Certificates
- In production, use trusted certificates (e.g., Let's Encrypt).
- Configure NGINX to enforce HTTPS.
### CORS & Security Headers
- Lock down CORS settings in production.
- Use security headers (e.g., HSTS, CSP).
### Logging & Monitoring
- Configure logging for production (e.g., ELK stack, Datadog).
- Set up basic monitoring (e.g., Prometheus, Grafana).
### Database Backup
- Regularly backup your production database.
- Example: Use `pg_dump` or a managed backup service.
### CI/CD & Automated Testing
- Run tests before deploying to production.
- Example CI/CD workflow:
```yaml
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branch: main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run Tests
run: npm test
- name: Deploy to Kubernetes
run: helm upgrade --install fusero ./chart -n fusero-prod -f chart/values.prod.yml
```
### Troubleshooting Production
- Common issues:
- Database connection errors: Check secrets and network policies.
- Pod crashes: Check logs with `kubectl logs <pod-name> -n fusero-prod`.
- Rollback: Use `helm rollback fusero <revision> -n fusero-prod`.
---

@ -0,0 +1,26 @@
backend:
env:
# Database
POSTGRES_NAME: "fusero-boilerplate-db"
POSTGRES_HOSTNAME: "postgres-service.fusero-prod.svc.cluster.local"
POSTGRES_PORT: "5432"
POSTGRES_USER: "root"
POSTGRES_PASSWORD: "REPLACE_ME"
# Admin User
DEFAULT_ADMIN_USERNAME: "admin"
DEFAULT_ADMIN_EMAIL: "admin@fusero.nl"
DEFAULT_ADMIN_PASSWORD: "REPLACE_ME"
# Security
ENCRYPTION_KEY: "REPLACE_ME"
JWT_SECRET: "REPLACE_ME"
# API Keys
CHATGPT_API_KEY: "REPLACE_ME"
CANVAS_API_KEY: "REPLACE_ME"
CANVAS_API_URL: "https://talnet.instructure.com/api/v1"
# Server
FASTIFY_PORT: "14000"
NODE_ENV: "production"

@ -1,2 +0,0 @@
# You can skip this if you manage secrets separately
# Included for completeness (values-dev.yaml handles them)

@ -0,0 +1,16 @@
# You can skip this if you manage secrets separately
# Included for completeness (values-dev.yaml handles them)
apiVersion: v1
kind: Secret
metadata:
name: fusero-backend-secrets
namespace: {{ .Values.global.namespace }}
type: Opaque
data:
POSTGRES_PASSWORD: {{ .Values.backend.env.POSTGRES_PASSWORD | b64enc }}
DEFAULT_ADMIN_PASSWORD: {{ .Values.backend.env.DEFAULT_ADMIN_PASSWORD | b64enc }}
ENCRYPTION_KEY: {{ .Values.backend.env.ENCRYPTION_KEY | b64enc }}
JWT_SECRET: {{ .Values.backend.env.JWT_SECRET | b64enc }}
CHATGPT_API_KEY: {{ .Values.backend.env.CHATGPT_API_KEY | b64enc }}
CANVAS_API_KEY: {{ .Values.backend.env.CANVAS_API_KEY | b64enc }}

@ -2,6 +2,7 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: fusero-backend-service name: fusero-backend-service
namespace: {{ .Values.global.namespace }}
spec: spec:
selector: selector:
app: fusero-backend app: fusero-backend

@ -2,6 +2,7 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: fusero-frontend-service name: fusero-frontend-service
namespace: {{ .Values.global.namespace }}
spec: spec:
selector: selector:
app: fusero-frontend app: fusero-frontend

@ -2,6 +2,7 @@ apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: postgres-service name: postgres-service
namespace: {{ .Values.global.namespace }}
spec: spec:
selector: selector:
app: postgres app: postgres

@ -0,0 +1,53 @@
global:
namespace: fusero-prod
security:
cors:
origin: "https://your-domain.com"
methods: "GET,POST,PUT,DELETE"
credentials: true
https:
enabled: true
certSecret: "fusero-tls-secret"
logging:
level: "info"
format: "json"
monitoring:
prometheus:
enabled: true
path: "/metrics"
backend:
image: fusero-backend:latest
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
env:
# Non-sensitive values only
NODE_ENV: "production"
FASTIFY_PORT: "14000"
CANVAS_API_URL: "https://talnet.instructure.com/api/v1"
frontend:
image: fusero-frontend:latest
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "300m"
memory: "256Mi"
postgres:
image: postgres:15
storage: 5Gi
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"

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

@ -10,16 +10,25 @@
"@": "src" "@": "src"
}, },
"scripts": { "scripts": {
"fc": "fastify cli", "build:ts": "rimraf dist && tsc",
"build:frontend:dev": "docker build -t fusero-frontend-dev:local -f frontend/Dockerfile.dev ./frontend",
"prebuild": "npm run lint",
"start": "npm run build:ts && fastify start -l info -r tsconfig-paths/register dist/src/app.js",
"dev": "npm run build:ts && concurrently -k -p '[{name}]' -n 'TypeScript,App,Watcher' -c 'teal.bold,orange.bold,purple.bold' 'npm:watch:ts' 'npm:dev:start' 'npm:watch:ts'",
"dev:start": "fastify start --ignore-watch=.ts$ -w -l info -P -r tsconfig-paths/register dist/src/app.js",
"watch:ts": "tsc -w",
"lint": "eslint src/**/*.{js,jsx,ts,tsx}",
"lint:fix": "eslint src/**/*.{js,jsx,ts,tsx} --fix",
"test": "jest", "test": "jest",
"test:unit": "tap test/services/**/*.ts", "test:unit": "tap test/services/**/*.ts",
"test:integration": "tap test/integration/**/*.ts", "test:integration": "tap test/integration/**/*.ts",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"test:coverage": "jest --coverage", "test:coverage": "jest --coverage",
"start": "npm run build:ts && fastify start -l info -r tsconfig-paths/register dist/src/app.js", "test:db": "ts-node -r tsconfig-paths/register src/database/test-connection.ts",
"prebuild": "npm run lint", "migration:create": "npx mikro-orm migration:create",
"build:ts": "rimraf dist && tsc", "migrate": "npx mikro-orm migration:up",
"build:frontend:dev": "docker build -t fusero-frontend-dev:local -f frontend/Dockerfile.dev ./frontend", "seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts",
"app:generate": "node ./utils/generate-app.js",
"k8s:dev:apply": "kubectl apply -f k8s/frontend/deployment.dev.yml", "k8s:dev:apply": "kubectl apply -f k8s/frontend/deployment.dev.yml",
"k8s:dev:delete": "kubectl delete deployment fusero-frontend-dev 2>/dev/null || true", "k8s:dev:delete": "kubectl delete deployment fusero-frontend-dev 2>/dev/null || true",
"k8s:dev:run": "kubectl port-forward svc/fusero-frontend-service 3000:80", "k8s:dev:run": "kubectl port-forward svc/fusero-frontend-service 3000:80",
@ -27,15 +36,6 @@
"k8s:dev:svc": "kubectl describe svc fusero-frontend-service", "k8s:dev:svc": "kubectl describe svc fusero-frontend-service",
"k8s:dev:deployment": "kubectl describe deployment fusero-frontend-dev", "k8s:dev:deployment": "kubectl describe deployment fusero-frontend-dev",
"k8s:get": "kubectl get pods,svc,deployment", "k8s:get": "kubectl get pods,svc,deployment",
"watch:ts": "tsc -w",
"dev": "npm run build:ts && concurrently -k -p \"[{name}]\" -n \"TypeScript,App\" -c \"yellow.bold,cyan.bold\" \"npm:watch:ts\" \"npm:dev:start\"",
"dev:start": "fastify start --ignore-watch=.ts$ -w -l info -P -r tsconfig-paths/register dist/src/app.js",
"app:generate": "node ./utils/generate-app.js",
"lint": "eslint src/**/*.{js,jsx,ts,tsx}",
"lint:fix": "eslint src/**/*.{js,jsx,ts,tsx} --fix",
"migration:create": "npx mikro-orm migration:create",
"seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts",
"test:db": "ts-node -r tsconfig-paths/register src/database/test-connection.ts",
"k8s:exec": "kubectl exec -it $POD_NAME -- /bin/sh" "k8s:exec": "kubectl exec -it $POD_NAME -- /bin/sh"
}, },
"keywords": [], "keywords": [],
@ -103,4 +103,4 @@
"git add" "git add"
] ]
} }
} }

@ -129,6 +129,11 @@ const app: FastifyPluginAsync = async (app, opts): Promise<void> => {
export async function buildApp(): Promise<FastifyInstance> { export async function buildApp(): Promise<FastifyInstance> {
const server = fastify(); const server = fastify();
await server.register(app); await server.register(app);
// Set the port to 14000
const port = process.env.PORT || 14000;
await server.listen({ port: Number(port), host: '0.0.0.0' });
return server; return server;
} }