mega update: k8s backend, frontend, database, pods, helm charts, k8s, load balancing, gitea-ci.yml explanded readme

This commit is contained in:
liquidrinu 2025-05-20 12:39:47 +02:00
parent b48b3dc027
commit ce4371d9e4
22 changed files with 693 additions and 262 deletions

12
.gitea-ci.yml Normal file

@ -0,0 +1,12 @@
image: lachlanevenson/k8s-helm:latest
stages:
- deploy
variables:
KUBECONFIG: /root/.kube/config # Adjust if you're mounting a kubeconfig differently
deploy:
stage: deploy
script:
- helm upgrade --install fusero ./chart -f ./chart/values-prod.yaml

9
.gitignore vendored

@ -114,4 +114,13 @@ test/types/index.js
dist dist
# general # general
docs
bkups bkups
# k8s
secrets.yml
# helm
values.dev.*
values.prod.*

@ -6,5 +6,6 @@
"tabWidth": 2, "tabWidth": 2,
"useTabs": false, "useTabs": false,
"printWidth": 144, "printWidth": 144,
"bracketSpacing": true "bracketSpacing": true,
"plugins": ["@helm/prettier-plugin-helm"]
} }

697
README.md

@ -1,269 +1,486 @@
# Fusero App Boilerplate # ⚡️ Fusero App Boilerplate
A full-stack application boilerplate with React frontend and Node.js backend. A full-stack application boilerplate with a React frontend and Node.js backend — powered by Fastify, Vite, PostgreSQL, Docker, and optional Kubernetes & Helm support. Built for modern dev workflows and AI-powered backend endpoint generation.
## Project Structure ---
## 📚 Table of Contents
- [⚡️ Fusero App Boilerplate](#-fusero-app-boilerplate)
- [📚 Table of Contents](#-table-of-contents)
- [📁 Project Structure](#-project-structure)
- [⚙️ Prerequisites](#-prerequisites)
- [💻 Development Setup](#-development-setup)
- [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)
- [🚀 Production Deployment](#-production-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)
- [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)
- [4. Restart the frontend deployment](#4-restart-the-frontend-deployment)
- [Port-Forwarding for Local Access](#port-forwarding-for-local-access)
- [Frontend (React app)](#frontend-react-app)
- [Backend (API)](#backend-api)
- [NGINX Backend Service Name: Docker Compose vs Kubernetes](#nginx-backend-service-name-docker-compose-vs-kubernetes)
- [How to update the NGINX config for Kubernetes](#how-to-update-the-nginx-config-for-kubernetes)
- [Cleaning Up Duplicate or Crashing Deployments and Pods in Kubernetes](#cleaning-up-duplicate-or-crashing-deployments-and-pods-in-kubernetes)
- [1. List deployments and pods](#1-list-deployments-and-pods)
- [2. Delete old or crashing deployments (example IDs from your cluster)](#2-delete-old-or-crashing-deployments-example-ids-from-your-cluster)
- [3. Delete old or crashing pods (example IDs from your cluster)](#3-delete-old-or-crashing-pods-example-ids-from-your-cluster)
- [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)
- [Connecting to the Database from Your Host (DBeaver, etc.)](#connecting-to-the-database-from-your-host-dbeaver-etc)
---
## 📁 Project Structure
```
fusero-app-boilerplate/ fusero-app-boilerplate/
├── frontend/ # React frontend application ├── frontend/ # React frontend application
├── backend/ # Node.js backend application ├── backend/ # Node.js backend application
├── docker-compose.yml # Production Docker configuration ├── docker-compose.yml # Production Docker configuration
└── docker-compose.dev.yml # Development Docker configuration ── docker-compose.dev.yml # Development Docker configuration
``` └── chart/ # Helm chart for Kubernetes deployment
## Prerequisites ---
## ⚙️ Prerequisites
- Node.js (v20 or higher) - Node.js (v20 or higher)
- npm (v9 or higher) - npm (v9 or higher)
- Docker and Docker Compose - Docker & Docker Compose
- Git - Git
## Development Setup ---
### Important Note: Database Must Run in Docker ## 💻 Development Setup
The PostgreSQL database must always run in Docker, regardless of your development setup choice. This ensures consistent database behavior across all environments.
To start the database: 🗃️ PostgreSQL must run in Docker for consistent behavior.
```bash
docker-compose up db
```
### Running Services Separately (Recommended for Development) Create volume and start the database:
docker volume create fusero-db-data
docker-compose up -d db
For better debugging experience, run the frontend and backend in separate terminal windows, while keeping the database in Docker: Backend setup:
cd backend
cp .env.example .env
npm install
npm run migrate
npm run seed
npm run dev &
cd ..
1. **First, ensure the database is running in Docker** Frontend setup:
```bash cd frontend
docker-compose up db cp .env.example .env
``` npm install
npm run dev &
cd ..
2. **Then, in separate terminal windows:** App is running:
Frontend → http://localhost:3000
Backend → http://localhost:14000
#### Terminal 1: Backend Service ---
```bash
### Alternate: Running Services in Separate Terminals
Terminal 1 (backend):
cd backend cd backend
npm install npm install
npm run dev npm run dev
```
The backend will be available at http://localhost:14000
#### Terminal 2: Frontend Service Terminal 2 (frontend):
```bash
cd frontend cd frontend
npm install npm install
npm run dev npm run dev
```
The frontend will be available at http://localhost:3000 ---
### Database Setup ## 🛠️ Environment Setup
1. **Create a New Volume** backend/.env:
- Ensure the database volume is created: POSTGRES_NAME=fusero-boilerplate-db
```bash POSTGRES_HOSTNAME=localhost
docker volume create fusero-db-data POSTGRES_PORT=19095
``` POSTGRES_USER=root
POSTGRES_PASSWORD=root123
2. **Run Migrations** JWT_SECRET=your_jwt_secret_key_here
- Apply database migrations to set up the schema:
```bash # For Kubernetes, these are set in chart/values.yaml:
cd backend # POSTGRES_NAME=fusero-boilerplate-db
npm run migrate # POSTGRES_HOSTNAME=postgres-service
``` # POSTGRES_PORT=19095
# POSTGRES_USER=root
3. **Seed the Database** # POSTGRES_PASSWORD=root123
- Populate the database with initial data:
```bash frontend/.env:
cd backend VITE_API_BASE_URL=http://localhost:14000/api/v1
npm run seed
``` ---
### Environment Setup ## 🚀 Production Deployment
1. **Backend Environment** 1. Build and run with Docker:
- Copy `.env.example` to `.env` in the backend directory docker-compose up --build
- Configure your environment variables:
``` 2. Apply migrations and seed inside backend container:
PORT=14000 docker exec -it fusero-app-backend npx mikro-orm migration:up
DB_HOST=localhost docker exec -it fusero-app-backend npm run seed
DB_PORT=19090
DB_USER=postgres 3. Ensure all required environment variables are configured.
DB_PASSWORD=postgres Never commit `.env` files.
DB_NAME=fusero
JWT_SECRET=your_jwt_secret_key_here ---
```
## 🌐 Frontend Routing in Production
2. **Frontend Environment**
- Copy `.env.example` to `.env` in the frontend directory In production, the frontend is served through NGINX.
- Set the API base URL:
``` NGINX configuration (important for React routing):
VITE_API_BASE_URL=http://localhost:14000/api/v1 location / {
``` try_files $uri $uri/ /index.html;
}
## Production Deployment
React Router Configuration:
1. **Build and Run with Docker** Use `basename="/"` in dev, and `basename="/dashboard"` in production.
```bash
docker-compose up --build Use relative paths in links:
``` Correct: to="canvas/canvas-endpoints"
Wrong: to="/dashboard/canvas/canvas-endpoints"
2. **Run Migrations and Seeders in Production**
After your containers are up, run the following commands to apply database migrations and seed data inside the backend container: ---
```bash
docker exec -it fusero-app-backend npx mikro-orm migration:up ## 🔐 HTTPS with Self-Signed Certificates
docker exec -it fusero-app-backend npm run seed
``` Generate a self-signed cert:
**Note:** These commands must be run inside the backend container so they use the correct Docker network and environment variables. openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./nginx/ssl/nginx.key -out ./nginx/ssl/nginx.crt
3. **Environment Variables** Ensure `docker-compose.yml` mounts the certs:
- Ensure all environment variables are properly set in your production environment volumes:
- Never commit `.env` files to version control - ./nginx/ssl:/etc/nginx/ssl
## Frontend Routing in Production Configure NGINX to use the cert in production.
In production, the frontend is served through nginx. To ensure client-side routing works correctly: ---
1. **Nginx Configuration** ## 🧠 Development Best Practices
- Ensure your nginx configuration includes the following directive to handle unknown routes:
```nginx - Always run the DB via Docker
location / { - Use `docker-compose.dev.yml` for development
try_files $uri $uri/ /index.html; - Never run PostgreSQL directly on host
} - Run frontend and backend separately for hot reload
``` - Use `.env.example` as a template
- Never commit `.env`
2. **React Router Configuration** - Commit `package-lock.json`
- Set the `basename` dynamically based on the environment: - Use meaningful commit messages
- In production, set `basename="/dashboard"`.
- In development, set `basename="/"`. ---
3. **Navigation Links** ## 📘 API Documentation
- Use relative paths in your navigation links (e.g., `to="canvas/canvas-endpoints"` instead of `to="/dashboard/canvas/canvas-endpoints"`).
After running the backend:
## HTTPS with Self-Signed Certificates
Development → http://localhost:14000/api-docs
To run the application with HTTPS using a self-signed certificate: Production → https://your-domain/api-docs
1. **Generate a Self-Signed Certificate** ---
```bash
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./nginx/ssl/nginx.key -out ./nginx/ssl/nginx.crt ## 🧩 ChatGPT-Powered Endpoint Creation
```
Prompts like "Create a course endpoint for Canvas" auto-generate API endpoints.
2. **Update Docker Compose**
- Ensure your `docker-compose.yml` mounts the certificate files in the nginx service: How it works:
```yaml 1. The frontend sends your prompt to `/api/v1/canvas-api/chatgpt/completions`
volumes: 2. If ChatGPT returns a valid endpoint JSON, it's POSTed to `/api/v1/canvas-api/endpoints`
- ./nginx/ssl:/etc/nginx/ssl 3. The UI auto-refreshes the endpoint list and shows a toast
```
Example Prompt:
3. **Nginx Configuration** Create a course endpoint for Canvas.
- Use the production nginx configuration that includes SSL settings.
Expected JSON:
## Development Best Practices {
"name": "Create Course",
1. **Database Management** "method": "POST",
- Always run the database in Docker "path": "/courses",
- Use `docker-compose.dev.yml` for development "description": "Creates a new course in Canvas."
- Never run PostgreSQL directly on your host machine }
2. **Running Services Separately** Developer Notes:
- For development, it's recommended to run frontend and backend in separate terminal windows - Frontend logic: frontend/src/components/CanvasEndpoints.tsx
- This allows for better debugging and hot-reloading - Backend API: /api/v1/canvas-api/endpoints
- You can see logs from each service clearly
---
3. **Code Organization**
- Frontend code should be in the `frontend/` directory ## 🧪 Troubleshooting
- Backend code should be in the `backend/` directory
- Shared types and utilities should be in their respective directories Port Conflicts:
docker ps
4. **Version Control** lsof -i :3000
- Commit `package-lock.json` files lsof -i :14000
- Don't commit `.env` files
- Use meaningful commit messages Database Issues:
Ensure DB is in Docker and configured correctly
## API Documentation Try restarting:
docker-compose -f docker-compose.dev.yml down
The backend API is documented using Swagger/OpenAPI. After starting the backend service, you can access the API documentation at: docker-compose -f docker-compose.dev.yml up db
- Development: http://localhost:14000/api-docs
- Production: http://your-domain/api-docs CORS Issues:
Check API base URL in frontend `.env`
## Troubleshooting Check backend CORS settings
Verify ports match and services are running
1. **Port Conflicts**
- If you encounter port conflicts, check which services are running: ---
```bash
docker ps ## 🤝 Contributing
```
- Or check for processes using the ports: 1. Create a branch
```bash 2. Make your changes
lsof -i :3000 3. Pass all tests
lsof -i :14000 4. Open a pull request
``` 5. Update docs if needed
2. **Database Issues** ---
- Ensure PostgreSQL is running in Docker
- Check database connection settings in `.env` ## 📄 License
- Verify database migrations are up to date
- If database issues persist, try: This project is licensed under the MIT License.
```bash See the LICENSE file for full details.
docker-compose -f docker-compose.dev.yml down
docker-compose -f docker-compose.dev.yml up db ---
```
## Kubernetes Troubleshooting & Redeployment Commands
3. **CORS Issues**
- If you see CORS errors, verify the frontend's API base URL If your backend is not picking up environment variables or is failing to connect to the database, follow these steps:
- Check backend CORS configuration
- Ensure both services are running on the correct ports ### 1. Rebuild the backend Docker image (after code/config changes)
```bash
## Contributing docker build -t fusero-backend-dev:local .
```
1. Create a new branch for your feature
2. Make your changes ### 2. (If using a remote registry) Push the image
3. Submit a pull request ```bash
4. Ensure all tests pass docker push <your-registry>/fusero-backend-dev:local
5. Update documentation as needed ```
## License ### 3. Upgrade the Helm release with the latest values
```bash
This project is licensed under the MIT License - see the LICENSE file for details. helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
```
## Technical Documentation: ChatGPT-Powered Endpoint Creation
### 4. Restart the backend deployment to pick up new images and env vars
### Overview ```bash
Developers can leverage the ChatGPT modal in the Canvas Endpoints UI to create new Canvas API endpoints using natural language prompts. When a user enters a prompt like "Create a course endpoint for Canvas", the system uses ChatGPT to: kubectl rollout restart deployment/fusero-backend -n fusero
```
1. Interpret the intent and generate a JSON object with the required fields for the endpoint (name, method, path, description, etc.).
2. Automatically submit this JSON to the backend endpoint creation API (`/api/v1/canvas-api/endpoints`). ### 5. Check backend pod environment variables
3. Refresh the endpoint list in the UI and display a success message. ```bash
kubectl get pods -n fusero
### How it Works # Replace <backend-pod-name> with the actual pod name from above
- **Prompt Handling:** kubectl exec -n fusero <backend-pod-name> -- printenv | grep POSTGRES
- The frontend sends the user's prompt to `/api/v1/canvas-api/chatgpt/completions`. ```
- ChatGPT is instructed to return only a JSON object suitable for the endpoint creation form.
- **Auto-Creation:** ### 6. Check backend pod logs for errors
- If the response is a valid endpoint JSON (with `name`, `method`, and `path`), the frontend posts it to `/api/v1/canvas-api/endpoints`. ```bash
- The endpoint list is refreshed and a toast notification is shown. kubectl logs <backend-pod-name> -n fusero --tail=50
- **Fallback:** ```
- If the response is not a valid endpoint JSON, it is displayed as a normal chat message.
### 7. If you change DB env vars or code, repeat steps 1-6
### Example Prompt
``` ---
Create a course endpoint for Canvas. Use the Canvas API docs to determine the correct path and required fields.
``` **Note:**
- Make sure your backend code does NOT load `.env` at runtime in Kubernetes. It should use the environment variables provided by the pod.
### Example ChatGPT Response - If you see connection errors to the DB, always check the pod's environment and logs as above.
```
{ ---
"name": "Create Course",
"method": "POST", ## Frontend Rebuild & Redeploy (Kubernetes)
"path": "/courses",
"description": "Creates a new course in Canvas." If you change the VITE_API_BASE_URL or any frontend environment variable, rebuild and redeploy the frontend:
}
``` ### 1. Rebuild the frontend Docker image
```bash
### Developer Notes docker build -t fusero-frontend-dev:local ./frontend
- The ChatGPT modal logic is in `frontend/src/components/CanvasEndpoints.tsx`. ```
- The backend endpoint creation API is `/api/v1/canvas-api/endpoints`.
- The system expects ChatGPT to return a JSON object with at least `name`, `method`, and `path`. ### 2. (If using a remote registry) Push the image
- The endpoint list is auto-refreshed after creation. ```bash
docker push <your-registry>/fusero-frontend-dev:local
```
### 3. Upgrade the Helm release
```bash
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
```
### 4. Restart the frontend deployment
```bash
kubectl rollout restart deployment/fusero-frontend -n fusero
```
---
## Port-Forwarding for Local Access
To access your services running in Kubernetes from your local machine, use these commands:
### Frontend (React app)
```bash
kubectl port-forward -n fusero svc/fusero-frontend-service 3000:80
```
- Access at: http://localhost:3000
### Backend (API)
```bash
kubectl port-forward -n fusero svc/fusero-backend-service 14000:14000
```
- Access at: http://localhost:14000
---
## NGINX Backend Service Name: Docker Compose vs Kubernetes
**If your frontend uses NGINX to proxy API requests, you must update the backend service name depending on your environment:**
- **Docker Compose/local:** The backend may be named `fusero-app-backend`.
- **Kubernetes:** The backend service is named `fusero-backend-service`.
### How to update the NGINX config for Kubernetes
Edit `frontend/nginx.conf`:
**Change this:**
```nginx
proxy_pass http://fusero-app-backend:14000/;
```
**To this:**
```nginx
proxy_pass http://fusero-backend-service:14000/;
```
Then rebuild and redeploy the frontend:
```bash
docker build -t fusero-frontend-dev:local ./frontend
# (push if needed)
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
kubectl rollout restart deployment/fusero-frontend -n fusero
```
**If you see an NGINX error like `host not found in upstream`, this is the cause!**
---
## Cleaning Up Duplicate or Crashing Deployments and Pods in Kubernetes
If you see multiple frontend or backend pods (or CrashLoopBackOff errors), clean up your namespace with these steps:
### 1. List deployments and pods
```bash
kubectl get deployments -n fusero
kubectl get pods -n fusero
```
### 2. Delete old or crashing deployments (example IDs from your cluster)
```bash
kubectl delete deployment fusero-frontend-65cb8db99d -n fusero
kubectl delete deployment fusero-frontend-74fcbb778 -n fusero
```
### 3. Delete old or crashing pods (example IDs from your cluster)
```bash
kubectl delete pod fusero-frontend-65cb8db99d-f2lhr -n fusero
kubectl delete pod fusero-frontend-74fcbb778-v89gm -n fusero
```
**Tip:** Only keep the latest, healthy pods and deployments. If in doubt, check with `kubectl get deployments -n fusero` and `kubectl get pods -n fusero` before deleting.
---
## Debugging Frontend Pod Crashes: NGINX SSL Certificate Errors
If your frontend pod crashes with an error like:
```
nginx: [emerg] cannot load certificate "/etc/nginx/certs/fusero-selfsigned.crt": BIO_new_file() failed (SSL: error:80000002:system library::No such file or directory)
```
This means NGINX is trying to load an SSL certificate that does not exist in the pod.
### How to fix for Kubernetes (Recommended)
1. Edit `frontend/nginx.conf`:
- Change:
```nginx
listen 14443 ssl;
ssl_certificate /etc/nginx/certs/fusero-selfsigned.crt;
ssl_certificate_key /etc/nginx/certs/fusero-selfsigned.key;
```
- To:
```nginx
listen 8080;
# (remove the ssl_certificate and ssl_certificate_key lines)
```
2. Rebuild the frontend Docker image:
```bash
docker build --no-cache -t fusero-frontend-dev:local ./frontend
```
3. (If using a remote registry) Push the image.
4. Redeploy with Helm:
```bash
helm upgrade fusero ./chart -n fusero -f chart/values.dev.yaml
```
5. Check pod status:
```bash
kubectl get pods -n fusero
```
**This will make NGINX listen on port 8080 without SSL, which is standard for in-cluster Kubernetes services.**
---
## Connecting to the Database from Your Host (DBeaver, etc.)
To connect to the Postgres database running in Kubernetes from your local machine (for example, using DBeaver or another SQL client):
1. **Port-forward the Postgres service:**
```bash
kubectl port-forward svc/postgres-service 5432:5432
```
- Keep this terminal open while you use your database client.
- If port 5432 is in use on your machine, you can use another local port (e.g., `15432:5432`) and connect to port 15432 in your client.
2. **Database connection settings:**
- **Host:** `localhost`
- **Port:** `5432` (or your chosen local port)
- **Database:** `fusero-boilerplate-db`
- **Username:** `root`
- **Password:** `root123`
3. **Open DBeaver (or your preferred client) and create a new Postgres connection using the above settings.**
4. **Test the connection.**
--- ---

13
architecture.excalidraw Normal file

@ -0,0 +1,13 @@
{
"type": "excalidraw",
"version": 2,
"source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor",
"elements": [],
"appState": {
"gridSize": 20,
"gridStep": 5,
"gridModeEnabled": false,
"viewBackgroundColor": "#ffffff"
},
"files": {}
}

6
chart/Chart.yaml Normal file

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

@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: fusero-backend
spec:
replicas: 1
selector:
matchLabels:
app: fusero-backend
template:
metadata:
labels:
app: fusero-backend
spec:
containers:
- name: backend
image: {{ .Values.backend.image }}
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
ports:
- containerPort: {{ .Values.backend.port }}
env:
{{- range $key, $val := .Values.backend.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}

@ -0,0 +1,25 @@
apiVersion: batch/v1
kind: Job
metadata:
name: fusero-backend-db-init
spec:
backoffLimit: 0
template:
metadata:
name: fusero-backend-db-init
spec:
containers:
- name: migrate-seed
image: {{ .Values.backend.image }}
command: ["/bin/sh", "-c"]
args:
- |
echo "Running migrations and seeds..." && \
npx mikro-orm migration:up && \
npm run seed
env:
{{- range $key, $val := .Values.backend.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}
restartPolicy: Never

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

@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: fusero-backend-service
spec:
selector:
app: fusero-backend
ports:
- protocol: TCP
port: {{ .Values.backend.port }}
targetPort: {{ .Values.backend.port }}

@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: fusero-frontend
spec:
replicas: 1
selector:
matchLabels:
app: fusero-frontend
template:
metadata:
labels:
app: fusero-frontend
spec:
containers:
- name: frontend
image: {{ .Values.frontend.image }}
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
ports:
- containerPort: {{ .Values.frontend.port }}
env:
{{- range $key, $val := .Values.frontend.env }}
- name: {{ $key }}
value: "{{ $val }}"
{{- end }}

@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: fusero-frontend-service
spec:
selector:
app: fusero-frontend
ports:
- protocol: TCP
port: 80
targetPort: {{ .Values.frontend.port }}

@ -0,0 +1,33 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: {{ .Values.postgres.image }}
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: {{ .Values.postgres.dbName }}
- name: POSTGRES_USER
value: {{ .Values.postgres.user }}
- name: POSTGRES_PASSWORD
value: {{ .Values.postgres.password }}
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: postgres-data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc-fresh

@ -0,0 +1,10 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc-fresh
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .Values.postgres.storage }}

@ -0,0 +1,10 @@
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
selector:
app: postgres
ports:
- protocol: TCP
port: 5432

@ -1,5 +1,5 @@
# Build stage # Build stage
FROM node:18-alpine as build FROM node:18-alpine AS build
WORKDIR /app WORKDIR /app

@ -1,18 +1,17 @@
FROM node:18-alpine FROM node:22
WORKDIR /app WORKDIR /app
# Copy package files # Copy package files and install dependencies
COPY package*.json ./ COPY package*.json ./
RUN npm ci
# Install dependencies # Copy .env and source code
RUN npm install COPY .env .
# Copy the rest of the application
COPY . . COPY . .
# Expose port 8080 # Expose the dev server port
EXPOSE 8080 EXPOSE 8080
# Start development server # Start the dev server — CORRECT host
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "8080"] CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "8080"]

@ -1,12 +1,13 @@
server { server {
listen 14443 ssl; # listen 14443 ssl;
listen 8080;
server_name _; server_name _;
ssl_certificate /etc/nginx/certs/fusero-selfsigned.crt; # ssl_certificate /etc/nginx/certs/fusero-selfsigned.crt;
ssl_certificate_key /etc/nginx/certs/fusero-selfsigned.key; # ssl_certificate_key /etc/nginx/certs/fusero-selfsigned.key;
location ^~ /api/ { location ^~ /api/ {
proxy_pass http://fusero-app-backend:14000/; proxy_pass http://fusero-backend-service:14000/;
proxy_http_version 1.1; proxy_http_version 1.1;
proxy_set_header Host $host; proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Real-IP $remote_addr;
@ -15,11 +16,8 @@ server {
} }
location / { location / {
proxy_pass http://host.docker.internal:8080; root /usr/share/nginx/html;
proxy_http_version 1.1; index index.html;
proxy_set_header Host $host; try_files $uri $uri/ /index.html;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
} }
} }

@ -6,6 +6,13 @@ export default defineConfig({
base: '/', base: '/',
server: { server: {
port: 8080, port: 8080,
proxy: {
'/api': {
target: 'http://localhost:14000',
changeOrigin: true,
secure: false,
}
}
}, },
build: { build: {
rollupOptions: { rollupOptions: {

@ -1,10 +1,11 @@
import dotenv from 'dotenv';
// Force reload `.env` even if it was previously loaded
dotenv.config({ override: true });
import { Options } from '@mikro-orm/core'; import { Options } from '@mikro-orm/core';
import { PostgreSqlDriver } from '@mikro-orm/postgresql'; import { PostgreSqlDriver } from '@mikro-orm/postgresql';
import { Migrator } from '@mikro-orm/migrations'; import { Migrator } from '@mikro-orm/migrations';
import dotenv from 'dotenv';
if (process.env.KUBERNETES_SERVICE_HOST === undefined) {
dotenv.config({ override: true });
}
const isProduction = process.env.NODE_ENV === 'production'; const isProduction = process.env.NODE_ENV === 'production';

@ -19,6 +19,14 @@
"start": "npm run build:ts && fastify start -l info -r tsconfig-paths/register dist/src/app.js", "start": "npm run build:ts && fastify start -l info -r tsconfig-paths/register dist/src/app.js",
"prebuild": "npm run lint", "prebuild": "npm run lint",
"build:ts": "rimraf dist && tsc", "build:ts": "rimraf dist && tsc",
"build:frontend:dev": "docker build -t fusero-frontend-dev:local -f frontend/Dockerfile.dev ./frontend",
"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:run": "kubectl port-forward svc/fusero-frontend-service 3000:80",
"k8s:dev:describe": "kubectl describe pod -l app=fusero-frontend",
"k8s:dev:svc": "kubectl describe svc fusero-frontend-service",
"k8s:dev:deployment": "kubectl describe deployment fusero-frontend-dev",
"k8s:get": "kubectl get pods,svc,deployment",
"watch:ts": "tsc -w", "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": "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", "dev:start": "fastify start --ignore-watch=.ts$ -w -l info -P -r tsconfig-paths/register dist/src/app.js",
@ -27,7 +35,8 @@
"lint:fix": "eslint src/**/*.{js,jsx,ts,tsx} --fix", "lint:fix": "eslint src/**/*.{js,jsx,ts,tsx} --fix",
"migration:create": "npx mikro-orm migration:create", "migration:create": "npx mikro-orm migration:create",
"seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts", "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" "test:db": "ts-node -r tsconfig-paths/register src/database/test-connection.ts",
"k8s:exec": "kubectl exec -it $POD_NAME -- /bin/sh"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",

@ -80,7 +80,14 @@ const app: FastifyPluginAsync = async (app, opts): Promise<void> => {
// Register CORS, JWT, and Cookies // Register CORS, JWT, and Cookies
app.register(fastifyCors, { app.register(fastifyCors, {
origin: ['http://localhost:3000', 'http://localhost:3001', 'http://localhost:8080', 'http://localhost:8081'], origin: process.env.CORS_ORIGIN
? process.env.CORS_ORIGIN.split(',').map(origin => origin.trim())
: [
'http://localhost:3000',
'http://localhost:3001',
'http://localhost:8080',
'http://localhost:8081'
],
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'Accept'], allowedHeaders: ['Content-Type', 'Authorization', 'Accept'],
credentials: true, credentials: true,