Compare commits
3 Commits
b3b7834166
...
c93505d7f0
Author | SHA1 | Date | |
---|---|---|---|
c93505d7f0 | |||
23acf3dafa | |||
3fe42fa8e4 |
103
.gitea-ci.yml
103
.gitea-ci.yml
@ -1,97 +1,12 @@
|
|||||||
version: 1.0
|
image: lachlanevenson/k8s-helm:latest
|
||||||
|
|
||||||
workflow:
|
stages:
|
||||||
name: Deploy to Production
|
- deploy
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
jobs:
|
variables:
|
||||||
build-and-deploy:
|
KUBECONFIG: /root/.kube/config # Adjust if you're mounting a kubeconfig differently
|
||||||
name: Build and Deploy
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
deploy:
|
||||||
uses: docker/setup-buildx-action@v2
|
stage: deploy
|
||||||
|
script:
|
||||||
- name: Login to Docker Registry
|
- helm upgrade --install fusero ./chart -f ./chart/values-prod.yaml
|
||||||
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.yaml << 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: Delete old migration/seed job
|
|
||||||
run: |
|
|
||||||
kubectl delete job fusero-backend-db-init -n fusero-prod || true
|
|
||||||
|
|
||||||
- name: Deploy to Kubernetes
|
|
||||||
run: |
|
|
||||||
helm upgrade --install fusero ./chart \
|
|
||||||
--namespace fusero-prod \
|
|
||||||
--create-namespace \
|
|
||||||
--values ./chart/values.prod.yaml \
|
|
||||||
--values ./chart/secrets.prod.yaml \
|
|
||||||
--set backend.image.repository=registry.liquidrinu.com/fusero-backend \
|
|
||||||
--set frontend.image.repository=registry.liquidrinu.com/fusero-frontend
|
|
||||||
|
|
||||||
- name: Wait for migration/seed job
|
|
||||||
run: |
|
|
||||||
kubectl wait --for=condition=complete --timeout=300s job/fusero-backend-db-init -n fusero-prod
|
|
||||||
JOB_STATUS=$(kubectl get job fusero-backend-db-init -n fusero-prod -o jsonpath='{.status.succeeded}')
|
|
||||||
if [ "$JOB_STATUS" != "1" ]; then
|
|
||||||
echo "Migration/seed job failed!" >&2
|
|
||||||
kubectl logs job/fusero-backend-db-init -n fusero-prod
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Verify Deployment
|
|
||||||
run: |
|
|
||||||
kubectl rollout status deployment/fusero-backend -n fusero-prod
|
|
||||||
kubectl rollout status deployment/fusero-frontend -n fusero-prod
|
|
||||||
|
19
.gitignore
vendored
19
.gitignore
vendored
@ -124,22 +124,3 @@ secrets.yml
|
|||||||
values.dev.*
|
values.dev.*
|
||||||
values.prod.*
|
values.prod.*
|
||||||
|
|
||||||
# Secrets
|
|
||||||
chart/secrets.prod.yaml
|
|
||||||
chart/secrets.*.yaml
|
|
||||||
*.env
|
|
||||||
.env.*
|
|
||||||
|
|
||||||
# Development values with secrets
|
|
||||||
chart/values.dev.yaml
|
|
||||||
|
|
||||||
# Production secrets
|
|
||||||
chart/secrets.prod.yaml
|
|
||||||
chart/secrets.*.yaml
|
|
||||||
|
|
||||||
# Keep templates and public configs
|
|
||||||
!chart/secrets.prod.template.yaml
|
|
||||||
!chart/values.prod.template.yaml
|
|
||||||
!chart/values.prod.public.yaml
|
|
||||||
|
|
||||||
.bkup/
|
|
||||||
|
385
README.md
385
README.md
@ -11,10 +11,6 @@ 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.yaml:](#for-kubernetes-these-are-set-in-chartvaluesyaml)
|
||||||
@ -23,12 +19,7 @@ A full-stack application boilerplate with a React frontend and Node.js backend
|
|||||||
- [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)
|
||||||
- [🐳 Docker Development](#-docker-development)
|
- [🚀 Production Deployment](#-production-deployment)
|
||||||
- [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,7 +44,6 @@ A full-stack application boilerplate with a React frontend and Node.js backend
|
|||||||
- [Port-Forwarding for Local Access](#port-forwarding-for-local-access)
|
- [Port-Forwarding for Local Access](#port-forwarding-for-local-access)
|
||||||
- [Frontend (React app)](#frontend-react-app)
|
- [Frontend (React app)](#frontend-react-app)
|
||||||
- [Backend (API)](#backend-api)
|
- [Backend (API)](#backend-api)
|
||||||
- [Database](#database)
|
|
||||||
- [NGINX Backend Service Name: Docker Compose vs Kubernetes](#nginx-backend-service-name-docker-compose-vs-kubernetes)
|
- [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)
|
- [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)
|
- [Cleaning Up Duplicate or Crashing Deployments and Pods in Kubernetes](#cleaning-up-duplicate-or-crashing-deployments-and-pods-in-kubernetes)
|
||||||
@ -63,68 +53,17 @@ 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)
|
|
||||||
- [🆕 Recent Improvements \& Troubleshooting](#-recent-improvements--troubleshooting)
|
|
||||||
- [🚀 Production Deployment Pipeline (CI/CD)](#-production-deployment-pipeline-cicd)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📁 Project Structure
|
## 📁 Project Structure
|
||||||
|
|
||||||
fusero-app-boilerplate/
|
fusero-app-boilerplate/
|
||||||
├── chart/ # Helm chart for Kubernetes
|
├── frontend/ # React frontend application
|
||||||
│ ├── Chart.yaml
|
├── backend/ # Node.js backend application
|
||||||
│ ├── values.dev.yaml
|
├── docker-compose.yml # Production Docker configuration
|
||||||
│ ├── values.prod.yaml
|
├── docker-compose.dev.yml # Development Docker configuration
|
||||||
│ └── templates/
|
└── chart/ # Helm chart for Kubernetes deployment
|
||||||
├── config/
|
|
||||||
├── coverage/
|
|
||||||
├── dist/
|
|
||||||
├── docs/
|
|
||||||
├── frontend/ # React frontend app
|
|
||||||
│ ├── public/
|
|
||||||
│ └── src/
|
|
||||||
├── mikro-orm.config.ts
|
|
||||||
├── nginx/
|
|
||||||
├── node_modules/
|
|
||||||
├── package.json
|
|
||||||
├── package-lock.json
|
|
||||||
├── docker-compose.yaml
|
|
||||||
├── docker-compose.dev.yaml
|
|
||||||
├── .gitignore
|
|
||||||
├── .gitea-ci.yaml
|
|
||||||
├── .prettierrc.json
|
|
||||||
├── .eslintrc.json
|
|
||||||
├── architecture.excalidraw
|
|
||||||
├── src/ # Node.js backend source
|
|
||||||
│ ├── apps/
|
|
||||||
│ ├── constants/
|
|
||||||
│ ├── database/
|
|
||||||
│ ├── middleware/
|
|
||||||
│ ├── plugins/
|
|
||||||
│ ├── shared/
|
|
||||||
│ ├── tests/
|
|
||||||
│ ├── types/
|
|
||||||
│ └── ...
|
|
||||||
├── test/
|
|
||||||
├── utils/
|
|
||||||
└── README.md
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -142,18 +81,14 @@ 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-dev-db-data
|
docker volume create fusero-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 ..
|
||||||
@ -207,50 +142,17 @@ VITE_API_BASE_URL=http://localhost:14000/api/v1
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🐳 Docker Development
|
## 🚀 Production Deployment
|
||||||
|
|
||||||
🗃️ 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 npm run migrate
|
docker exec -it fusero-app-backend npx mikro-orm migration:up
|
||||||
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.
|
||||||
|
Never commit `.env` files.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -277,7 +179,7 @@ Wrong: to="/dashboard/canvas/canvas-endpoints"
|
|||||||
Generate a self-signed cert:
|
Generate a self-signed cert:
|
||||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./nginx/ssl/nginx.key -out ./nginx/ssl/nginx.crt
|
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./nginx/ssl/nginx.key -out ./nginx/ssl/nginx.crt
|
||||||
|
|
||||||
Ensure `docker-compose.yaml` mounts the certs:
|
Ensure `docker-compose.yml` mounts the certs:
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx/ssl:/etc/nginx/ssl
|
- ./nginx/ssl:/etc/nginx/ssl
|
||||||
|
|
||||||
@ -288,7 +190,7 @@ Configure NGINX to use the cert in production.
|
|||||||
## 🧠 Development Best Practices
|
## 🧠 Development Best Practices
|
||||||
|
|
||||||
- Always run the DB via Docker
|
- Always run the DB via Docker
|
||||||
- Use `docker-compose.dev.yaml` for development
|
- Use `docker-compose.dev.yml` for development
|
||||||
- Never run PostgreSQL directly on host
|
- Never run PostgreSQL directly on host
|
||||||
- Run frontend and backend separately for hot reload
|
- Run frontend and backend separately for hot reload
|
||||||
- Use `.env.example` as a template
|
- Use `.env.example` as a template
|
||||||
@ -343,8 +245,8 @@ lsof -i :14000
|
|||||||
Database Issues:
|
Database Issues:
|
||||||
Ensure DB is in Docker and configured correctly
|
Ensure DB is in Docker and configured correctly
|
||||||
Try restarting:
|
Try restarting:
|
||||||
docker-compose -f docker-compose.dev.yaml down
|
docker-compose -f docker-compose.dev.yml down
|
||||||
docker-compose -f docker-compose.dev.yaml up db
|
docker-compose -f docker-compose.dev.yml up db
|
||||||
|
|
||||||
CORS Issues:
|
CORS Issues:
|
||||||
Check API base URL in frontend `.env`
|
Check API base URL in frontend `.env`
|
||||||
@ -448,22 +350,16 @@ To access your services running in Kubernetes from your local machine, use these
|
|||||||
|
|
||||||
### Frontend (React app)
|
### Frontend (React app)
|
||||||
```bash
|
```bash
|
||||||
kubectl port-forward -n fusero-dev svc/fusero-frontend-service 3000:80
|
kubectl port-forward -n fusero svc/fusero-frontend-service 3000:80
|
||||||
```
|
```
|
||||||
- Access at: http://localhost:3000
|
- Access at: http://localhost:3000
|
||||||
|
|
||||||
### Backend (API)
|
### Backend (API)
|
||||||
```bash
|
```bash
|
||||||
kubectl port-forward -n fusero-dev svc/fusero-backend-service 14000:14000
|
kubectl port-forward -n fusero svc/fusero-backend-service 14000:14000
|
||||||
```
|
```
|
||||||
- Access at: http://localhost:14000
|
- Access at: http://localhost:14000
|
||||||
|
|
||||||
### Database
|
|
||||||
```bash
|
|
||||||
kubectl port-forward -n fusero-dev svc/postgres-service 5432:5432
|
|
||||||
```
|
|
||||||
- Access at: localhost:5432
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## NGINX Backend Service Name: Docker Compose vs Kubernetes
|
## NGINX Backend Service Name: Docker Compose vs Kubernetes
|
||||||
@ -588,252 +484,3 @@ 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.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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.yaml`, `frontend-service.yaml`, `postgres-service.yaml`) now use a namespace variable.
|
|
||||||
- The development values file (`chart/values.dev.yaml`) 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.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
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.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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.yaml`
|
|
||||||
- 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.yaml` 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.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
### 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`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🆕 Recent Improvements & Troubleshooting
|
|
||||||
|
|
||||||
- **Consistent File Extensions:** All Kubernetes and Helm YAML files now use the `.yaml` extension for consistency.
|
|
||||||
- **Secrets Management:**
|
|
||||||
- Development secrets are stored in `chart/secrets.dev.yaml` (gitignored).
|
|
||||||
- Production secrets are generated by CI/CD as `chart/secrets.prod.yaml` from Gitea secrets.
|
|
||||||
- All values files (`values.dev.yaml`, `values.prod.yaml`) reference secrets via environment variables.
|
|
||||||
- **CORS Configuration:**
|
|
||||||
- For local development, set `CORS_ORIGIN: "http://localhost:3000"` in `chart/values.dev.yaml` to allow credentialed requests from the frontend.
|
|
||||||
- Do **not** use `*` for CORS origin if you need credentials.
|
|
||||||
- **Kubernetes Job Immutability:**
|
|
||||||
- If you update environment variables or secrets, you must delete the old migration/seed job before redeploying:
|
|
||||||
```bash
|
|
||||||
kubectl delete job fusero-backend-db-init -n fusero-dev
|
|
||||||
helm upgrade --install fusero ./chart -n fusero-dev -f chart/values.dev.yaml -f chart/secrets.dev.yaml
|
|
||||||
```
|
|
||||||
- **Port Forwarding for Local Access:**
|
|
||||||
- Backend:
|
|
||||||
```bash
|
|
||||||
kubectl port-forward -n fusero-dev svc/fusero-backend-service 14000:14000
|
|
||||||
```
|
|
||||||
- Frontend:
|
|
||||||
```bash
|
|
||||||
kubectl port-forward -n fusero-dev svc/fusero-frontend-service 3000:80
|
|
||||||
```
|
|
||||||
- Database:
|
|
||||||
```bash
|
|
||||||
kubectl port-forward -n fusero-dev svc/postgres-service 5432:5432
|
|
||||||
```
|
|
||||||
- **Testing Login with curl:**
|
|
||||||
```bash
|
|
||||||
curl -i -X POST http://localhost:14000/api/v1/app/users/login \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Origin: http://localhost:3000" \
|
|
||||||
-d '{"username":"admin","password":"admin123"}'
|
|
||||||
```
|
|
||||||
- **Troubleshooting 401 Errors:**
|
|
||||||
- If login fails after a redeploy:
|
|
||||||
- Ensure secrets and values are in sync.
|
|
||||||
- Re-run the seed job as above.
|
|
||||||
- Check backend logs for authentication errors:
|
|
||||||
```bash
|
|
||||||
kubectl logs -n fusero-dev -l app=fusero-backend --tail=100
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Production Deployment Pipeline (CI/CD)
|
|
||||||
|
|
||||||
- On every push/merge to `main`, the Gitea CI/CD pipeline will:
|
|
||||||
1. Build and push Docker images for backend and frontend.
|
|
||||||
2. Generate `secrets.prod.yaml` from Gitea CI/CD secrets.
|
|
||||||
3. **Delete the old migration/seed job** (`fusero-backend-db-init`) to ensure a fresh run.
|
|
||||||
4. Deploy the app with Helm, which triggers the migration/seed job.
|
|
||||||
5. **Wait for the migration/seed job to complete.**
|
|
||||||
6. **Fail the pipeline if the job fails** (with logs for debugging).
|
|
||||||
7. Verify the deployment.
|
|
||||||
|
|
||||||
- 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`.
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
name: fusero
|
name: fusero
|
||||||
description: Fusero App Boilerplate Helm Chart
|
description: Fusero application Helm chart
|
||||||
type: application
|
type: application
|
||||||
version: 0.1.0
|
version: 0.1.0
|
||||||
appVersion: "1.0.0"
|
appVersion: "1.0.0"
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fusero
|
|
||||||
description: Fusero App Boilerplate Helm Chart
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "1.0.0"
|
|
@ -1,16 +1,2 @@
|
|||||||
# You can skip this if you manage secrets separately
|
# You can skip this if you manage secrets separately
|
||||||
# Included for completeness (values-dev.yaml handles them)
|
# 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,7 +2,6 @@ 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,7 +2,6 @@ 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
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: fusero-app-ingress
|
|
||||||
namespace: fusero-prod
|
|
||||||
annotations:
|
|
||||||
traefik.ingress.kubernetes.io/router.entrypoints: web
|
|
||||||
spec:
|
|
||||||
rules:
|
|
||||||
- host: app.fusero.nl
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
- path: /api
|
|
||||||
pathType: Prefix
|
|
||||||
backend:
|
|
||||||
service:
|
|
||||||
name: fusero-backend-service
|
|
||||||
port:
|
|
||||||
number: 14000
|
|
||||||
- path: /
|
|
||||||
pathType: Prefix
|
|
||||||
backend:
|
|
||||||
service:
|
|
||||||
name: fusero-frontend-service
|
|
||||||
port:
|
|
||||||
number: 80
|
|
@ -1,18 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: postgres-config
|
|
||||||
data:
|
|
||||||
pg_hba.conf: |
|
|
||||||
# TYPE DATABASE USER ADDRESS METHOD
|
|
||||||
local all all trust
|
|
||||||
host all all 127.0.0.1/32 trust
|
|
||||||
host all all ::1/128 trust
|
|
||||||
host all all 0.0.0.0/0 md5
|
|
||||||
postgresql.conf: |
|
|
||||||
listen_addresses = '*'
|
|
||||||
max_connections = 100
|
|
||||||
shared_buffers = 128MB
|
|
||||||
dynamic_shared_memory_type = posix
|
|
||||||
max_wal_size = 1GB
|
|
||||||
min_wal_size = 80MB
|
|
@ -27,16 +27,7 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- mountPath: /var/lib/postgresql/data
|
- mountPath: /var/lib/postgresql/data
|
||||||
name: postgres-data
|
name: postgres-data
|
||||||
- mountPath: /etc/postgresql/pg_hba.conf
|
|
||||||
name: postgres-config
|
|
||||||
subPath: pg_hba.conf
|
|
||||||
- mountPath: /etc/postgresql/postgresql.conf
|
|
||||||
name: postgres-config
|
|
||||||
subPath: postgresql.conf
|
|
||||||
volumes:
|
volumes:
|
||||||
- name: postgres-data
|
- name: postgres-data
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: postgres-pvc-fresh
|
claimName: postgres-pvc-fresh
|
||||||
- name: postgres-config
|
|
||||||
configMap:
|
|
||||||
name: postgres-config
|
|
||||||
|
@ -2,7 +2,6 @@ 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
|
||||||
|
34
chart/values.dev.yaml
Normal file
34
chart/values.dev.yaml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
global:
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
backend:
|
||||||
|
image: fusero-backend-dev:local
|
||||||
|
port: 14000
|
||||||
|
env:
|
||||||
|
CORS_ORIGIN: "*"
|
||||||
|
POSTGRES_NAME: fusero-boilerplate-db
|
||||||
|
POSTGRES_HOSTNAME: postgres-service
|
||||||
|
POSTGRES_USER: root
|
||||||
|
POSTGRES_PASSWORD: root123
|
||||||
|
POSTGRES_PORT: "5432"
|
||||||
|
DEFAULT_ADMIN_USERNAME: admin
|
||||||
|
DEFAULT_ADMIN_EMAIL: darren@fusero.nl
|
||||||
|
DEFAULT_ADMIN_PASSWORD: admin123
|
||||||
|
ENCRYPTION_KEY: d3680f1c027e865e1da5c2be8b0be20c43f70a8107071e61df15cab6df4357cf
|
||||||
|
JWT_SECRET: sdfj94mfm430f72m3487rdsjiy7834n9rnf934n8r3n490fn4u83fh894hr9nf0
|
||||||
|
CHATGPT_API_KEY: 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
|
||||||
|
CANVAS_API_KEY: 17601~vLkPEraKTtCmxrNx48TH9JW8ePtUPG2tHLZu8mauAuUeyXePXKY67axYaWRrN43x
|
||||||
|
CANVAS_API_URL: https://talnet.instructure.com/api/v1
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
image: fusero-frontend-dev:devserver
|
||||||
|
port: 8080
|
||||||
|
env:
|
||||||
|
VITE_API_BASE_URL: http://localhost:14000
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:15
|
||||||
|
storage: 1Gi
|
||||||
|
dbName: fusero-boilerplate-db
|
||||||
|
user: root
|
||||||
|
password: root123
|
@ -1,53 +0,0 @@
|
|||||||
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"
|
|
22
chart/values.prod.yml
Normal file
22
chart/values.prod.yml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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
|
27
frontend/nginx.conf.bkup
Normal file
27
frontend/nginx.conf.bkup
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name _;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Serve favicon files
|
||||||
|
location /favicon/ {
|
||||||
|
alias /usr/share/nginx/html/dist/favicon/;
|
||||||
|
access_log off;
|
||||||
|
expires max;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Proxy API requests to the backend
|
||||||
|
location /api {
|
||||||
|
proxy_pass http://fusero-app-backend:14000;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
}
|
1
frontend/src/vite-env.d.ts
vendored
Normal file
1
frontend/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
30
package.json
30
package.json
@ -10,32 +10,32 @@
|
|||||||
"@": "src"
|
"@": "src"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:ts": "rimraf dist && tsc",
|
"fc": "fastify cli",
|
||||||
"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",
|
||||||
"test:db": "ts-node -r tsconfig-paths/register src/database/test-connection.ts",
|
"start": "npm run build:ts && fastify start -l info -r tsconfig-paths/register dist/src/app.js",
|
||||||
"migration:create": "npx mikro-orm migration:create",
|
"prebuild": "npm run lint",
|
||||||
"migrate": "npx mikro-orm migration:up",
|
"build:ts": "rimraf dist && tsc",
|
||||||
"seed": "ts-node -r tsconfig-paths/register src/database/seeds/run-seed.ts",
|
"build:frontend:dev": "docker build -t fusero-frontend-dev:local -f frontend/Dockerfile.dev ./frontend",
|
||||||
"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.yaml",
|
|
||||||
"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",
|
||||||
"k8s:dev:describe": "kubectl describe pod -l app=fusero-frontend",
|
"k8s:dev:describe": "kubectl describe pod -l app=fusero-frontend",
|
||||||
"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": [],
|
||||||
|
@ -129,11 +129,6 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
src/plugins/Crypto.ts
Normal file
33
src/plugins/Crypto.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// import fp from 'fastify-plugin';
|
||||||
|
// import crypto from 'crypto';
|
||||||
|
// import { FastifyInstance, FastifyPluginAsync } from 'fastify';
|
||||||
|
|
||||||
|
// const ENCRYPTION_KEY = process.env.ENCRYPTION_KEY as string; // Ensure this is 32 bytes for AES-256
|
||||||
|
// const IV_LENGTH = 16; // AES block size
|
||||||
|
|
||||||
|
// const cryptoPlugin: FastifyPluginAsync = async (fastify: FastifyInstance) => {
|
||||||
|
// fastify.decorate('encrypt', (text: string): string => {
|
||||||
|
// const iv = crypto.randomBytes(IV_LENGTH);
|
||||||
|
// const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(ENCRYPTION_KEY), iv);
|
||||||
|
// let encrypted = cipher.update(text);
|
||||||
|
// encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||||
|
// return iv.toString('hex') + ':' + encrypted.toString('hex');
|
||||||
|
// });
|
||||||
|
|
||||||
|
// fastify.decorate('decrypt', (text: string): string => {
|
||||||
|
// const textParts = text.split(':');
|
||||||
|
// const iv = Buffer.from(textParts.shift()!, 'hex');
|
||||||
|
// const encryptedText = Buffer.from(textParts.join(':'), 'hex');
|
||||||
|
// const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(ENCRYPTION_KEY), iv);
|
||||||
|
// let decrypted = decipher.update(encryptedText);
|
||||||
|
// decrypted = Buffer.concat([decrypted, decipher.final()]);
|
||||||
|
// return decrypted.toString();
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export default fp(cryptoPlugin, {
|
||||||
|
// name: 'cryptoPlugin',
|
||||||
|
// decorators: {
|
||||||
|
// fastify: ['encrypt', 'decrypt'],
|
||||||
|
// },
|
||||||
|
// });
|
20
src/plugins/JWT.ts
Normal file
20
src/plugins/JWT.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// import { FastifyPluginAsync } from 'fastify';
|
||||||
|
// import fJwt, { FastifyJWTOptions } from '@fastify/jwt';
|
||||||
|
|
||||||
|
// const jwtPlugin: FastifyPluginAsync<FastifyJWTOptions> = async (fastify) => {
|
||||||
|
// await fastify.register(fJwt, {
|
||||||
|
// secret: process.env.JWT_SECRET || 'your-secret-here',
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const authenticateDecorator: FastifyPluginAsync = async (fastify) => {
|
||||||
|
// fastify.decorate('authenticate', async (request, reply) => {
|
||||||
|
// try {
|
||||||
|
// await request.jwtVerify();
|
||||||
|
// } catch (err) {
|
||||||
|
// reply.send(err);
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export { jwtPlugin, authenticateDecorator };
|
15
src/shared/exceptions/TooManyRequests.ts
Normal file
15
src/shared/exceptions/TooManyRequests.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// import { HttpStatusCode } from 'axios';
|
||||||
|
|
||||||
|
// class TooManyRequests extends Error {
|
||||||
|
// public httpErrorStatusCode = HttpStatusCode.TooManyRequests;
|
||||||
|
// constructor(msg: string, customErrorCode?: HttpStatusCode) {
|
||||||
|
// super(msg);
|
||||||
|
|
||||||
|
// this.httpErrorStatusCode = this.httpErrorStatusCode ?? customErrorCode;
|
||||||
|
|
||||||
|
// // Set the prototype explicitly.
|
||||||
|
// Object.setPrototypeOf(this, TooManyRequests.prototype);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export default TooManyRequests;
|
Loading…
Reference in New Issue
Block a user