diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/.env.example b/PROJECTS/advanced/monitor-the-situation-dashboard/.env.example new file mode 100644 index 00000000..39b2128b --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/.env.example @@ -0,0 +1,28 @@ +# ©AngelaMos | 2026 +# .env.example + +APP_NAME=monitor +PUBLIC_URL=http://localhost:8430 + +NGINX_HOST_PORT=8430 +BACKEND_HOST_PORT=5430 +FRONTEND_HOST_PORT=3430 +POSTGRES_HOST_PORT=5431 +REDIS_HOST_PORT=6430 + +POSTGRES_USER=monitor +POSTGRES_PASSWORD=changeme +POSTGRES_DB=monitor + +REDIS_PASSWORD= + +JWT_SECRET= +NOTIFICATION_ENCRYPTION_KEY= + +NVD_API_KEY= +CF_RADAR_TOKEN= +GREYNOISE_API_KEY= + +CLOUDFLARE_TUNNEL_TOKEN= + +VITE_API_URL=/api diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/Makefile b/PROJECTS/advanced/monitor-the-situation-dashboard/Makefile new file mode 100644 index 00000000..d929628f --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/Makefile @@ -0,0 +1,107 @@ +# ©AngelaMos | 2026 +# Makefile + +.DEFAULT_GOAL := help +SHELL := /bin/bash + +COMPOSE_PROD := docker compose -f compose.yml +COMPOSE_DEV := docker compose -f dev.compose.yml +COMPOSE_TUN := docker compose -f compose.yml -f cloudflared.compose.yml + +.PHONY: help up up-dev up-tunnel down down-dev logs logs-dev ps ps-dev migrate migrate-dev psql redis-cli backend-shell frontend-shell tidy fmt test build-prod stop clean + +help: + @echo 'Monitor the Situation — Make targets:' + @echo '' + @echo ' Production:' + @echo ' up start production stack (no tunnel)' + @echo ' up-tunnel start production stack + cloudflared' + @echo ' down stop production stack' + @echo ' logs tail production logs' + @echo ' ps status of production services' + @echo '' + @echo ' Development:' + @echo ' up-dev start dev stack (vite + air)' + @echo ' down-dev stop dev stack' + @echo ' logs-dev tail dev logs' + @echo ' ps-dev status of dev services' + @echo '' + @echo ' Database:' + @echo ' migrate run goose migrations against prod db' + @echo ' migrate-dev run goose migrations against dev db' + @echo ' psql psql shell into dev db' + @echo ' redis-cli redis-cli shell into dev redis' + @echo '' + @echo ' Backend:' + @echo ' backend-shell shell into the dev backend container' + @echo ' test run all backend tests with -race' + @echo ' fmt format Go code' + @echo ' tidy go mod tidy' + @echo '' + @echo ' Frontend:' + @echo ' frontend-shell shell into the dev frontend container' + @echo '' + +up: + $(COMPOSE_PROD) up -d --build + +up-tunnel: + $(COMPOSE_TUN) up -d --build + +up-dev: + $(COMPOSE_DEV) up -d --build + +down: + $(COMPOSE_PROD) down + +down-dev: + $(COMPOSE_DEV) down + +logs: + $(COMPOSE_PROD) logs -f --tail=200 + +logs-dev: + $(COMPOSE_DEV) logs -f --tail=200 + +ps: + $(COMPOSE_PROD) ps + +ps-dev: + $(COMPOSE_DEV) ps + +migrate: + $(COMPOSE_PROD) exec backend sh -c 'goose -dir /migrations postgres "$$DATABASE_URL" up' + +migrate-dev: + $(COMPOSE_DEV) exec backend sh -c 'cd /app && goose -dir migrations postgres "$$DATABASE_URL" up' + +psql: + $(COMPOSE_DEV) exec postgres psql -U $${POSTGRES_USER:-monitor} -d $${POSTGRES_DB:-monitor} + +redis-cli: + $(COMPOSE_DEV) exec redis redis-cli + +backend-shell: + $(COMPOSE_DEV) exec backend sh + +frontend-shell: + $(COMPOSE_DEV) exec frontend sh + +test: + cd backend && go test -race -count=1 ./... + +fmt: + cd backend && gofumpt -w . && goimports -w . + +tidy: + cd backend && go mod tidy + +build-prod: + $(COMPOSE_PROD) build + +stop: + $(COMPOSE_DEV) stop ; $(COMPOSE_PROD) stop + +clean: stop + $(COMPOSE_DEV) down -v + $(COMPOSE_PROD) down -v diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/cloudflared.compose.yml b/PROJECTS/advanced/monitor-the-situation-dashboard/cloudflared.compose.yml new file mode 100644 index 00000000..d84e01f1 --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/cloudflared.compose.yml @@ -0,0 +1,22 @@ +# ©AngelaMos | 2026 +# cloudflared.compose.yml + +services: + cloudflared: + image: cloudflare/cloudflared:latest + container_name: ${APP_NAME:-monitor}-tunnel + command: tunnel run --token ${CLOUDFLARE_TUNNEL_TOKEN} + networks: + - backend + depends_on: + nginx: + condition: service_started + deploy: + resources: + limits: + cpus: '0.5' + memory: 128M + reservations: + cpus: '0.1' + memory: 32M + restart: unless-stopped diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/compose.yml b/PROJECTS/advanced/monitor-the-situation-dashboard/compose.yml new file mode 100644 index 00000000..b3d9d08c --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/compose.yml @@ -0,0 +1,130 @@ +# ©AngelaMos | 2026 +# compose.yml + +name: ${APP_NAME:-monitor} + +services: + nginx: + build: + context: . + dockerfile: conf/docker/prod/vite.docker + container_name: ${APP_NAME:-monitor}-nginx + ports: + - "${NGINX_HOST_PORT:-8430}:80" + depends_on: + backend: + condition: service_healthy + networks: + - frontend + - backend + deploy: + resources: + limits: + cpus: '1.0' + memory: 256M + reservations: + cpus: '0.25' + memory: 64M + restart: unless-stopped + + backend: + build: + context: . + dockerfile: conf/docker/prod/go.docker + container_name: ${APP_NAME:-monitor}-backend + expose: + - "8080" + env_file: + - .env + environment: + - APP_ENVIRONMENT=production + - DATABASE_URL=postgres://${POSTGRES_USER:-monitor}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-monitor}?sslmode=disable + - REDIS_URL=redis://:${REDIS_PASSWORD}@redis:6379/0 + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + networks: + - backend + deploy: + resources: + limits: + cpus: '2.0' + memory: 1G + reservations: + cpus: '0.5' + memory: 256M + healthcheck: + test: ["CMD", "/app", "-healthcheck"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 30s + restart: unless-stopped + + postgres: + image: postgres:17-alpine + container_name: ${APP_NAME:-monitor}-postgres + environment: + POSTGRES_USER: ${POSTGRES_USER:-monitor} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB:-monitor} + volumes: + - pgdata:/var/lib/postgresql/data + networks: + - backend + deploy: + resources: + limits: + cpus: '1.0' + memory: 512M + reservations: + cpus: '0.25' + memory: 128M + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-monitor} -d ${POSTGRES_DB:-monitor}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + restart: unless-stopped + + redis: + image: redis:7-alpine + container_name: ${APP_NAME:-monitor}-redis + command: redis-server --appendonly yes ${REDIS_PASSWORD:+--requirepass ${REDIS_PASSWORD}} + volumes: + - redisdata:/data + networks: + - backend + deploy: + resources: + limits: + cpus: '0.5' + memory: 256M + reservations: + cpus: '0.1' + memory: 64M + healthcheck: + test: ["CMD-SHELL", "redis-cli ${REDIS_PASSWORD:+-a ${REDIS_PASSWORD}} ping | grep PONG"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + +networks: + frontend: + driver: bridge + ipam: + config: + - subnet: 10.203.83.0/24 + backend: + driver: bridge + ipam: + config: + - subnet: 10.203.84.0/24 + +volumes: + pgdata: + redisdata: diff --git a/PROJECTS/advanced/monitor-the-situation-dashboard/dev.compose.yml b/PROJECTS/advanced/monitor-the-situation-dashboard/dev.compose.yml new file mode 100644 index 00000000..465186c6 --- /dev/null +++ b/PROJECTS/advanced/monitor-the-situation-dashboard/dev.compose.yml @@ -0,0 +1,126 @@ +# ©AngelaMos | 2026 +# dev.compose.yml + +name: ${APP_NAME:-monitor}-dev + +services: + nginx: + image: nginx:1.27-alpine + container_name: ${APP_NAME:-monitor}-nginx-dev + ports: + - "${NGINX_HOST_PORT:-8430}:80" + volumes: + - ./conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./conf/nginx/dev.nginx:/etc/nginx/conf.d/default.conf:ro + depends_on: + backend: + condition: service_healthy + frontend: + condition: service_started + networks: + - frontend + - backend + restart: unless-stopped + + backend: + build: + context: . + dockerfile: conf/docker/dev/go.docker + container_name: ${APP_NAME:-monitor}-backend-dev + ports: + - "${BACKEND_HOST_PORT:-5430}:8080" + volumes: + - ./backend:/app + - go-mod-cache:/go/pkg/mod + env_file: + - .env + environment: + - APP_ENVIRONMENT=development + - DATABASE_URL=postgres://${POSTGRES_USER:-monitor}:${POSTGRES_PASSWORD:-monitor}@postgres:5432/${POSTGRES_DB:-monitor}?sslmode=disable + - REDIS_URL=redis://redis:6379/0 + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + networks: + - backend + healthcheck: + test: ["CMD-SHELL", "wget -q -O- http://localhost:8080/api/v1/healthz || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + restart: unless-stopped + + frontend: + build: + context: . + dockerfile: conf/docker/dev/vite.docker + container_name: ${APP_NAME:-monitor}-frontend-dev + ports: + - "${FRONTEND_HOST_PORT:-3430}:5173" + volumes: + - ./frontend:/app + - frontend-node-modules:/app/node_modules + environment: + - VITE_API_URL=${VITE_API_URL:-/api} + networks: + - frontend + restart: unless-stopped + + postgres: + image: postgres:17-alpine + container_name: ${APP_NAME:-monitor}-postgres-dev + ports: + - "${POSTGRES_HOST_PORT:-5431}:5432" + environment: + POSTGRES_USER: ${POSTGRES_USER:-monitor} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-monitor} + POSTGRES_DB: ${POSTGRES_DB:-monitor} + volumes: + - pgdata-dev:/var/lib/postgresql/data + networks: + - backend + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-monitor} -d ${POSTGRES_DB:-monitor}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + restart: unless-stopped + + redis: + image: redis:7-alpine + container_name: ${APP_NAME:-monitor}-redis-dev + ports: + - "${REDIS_HOST_PORT:-6430}:6379" + command: redis-server --appendonly yes + volumes: + - redisdata-dev:/data + networks: + - backend + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + +networks: + frontend: + driver: bridge + ipam: + config: + - subnet: 10.201.71.0/24 + backend: + driver: bridge + ipam: + config: + - subnet: 10.201.72.0/24 + +volumes: + pgdata-dev: + redisdata-dev: + go-mod-cache: + frontend-node-modules: