diff --git a/.gitignore b/.gitignore index b8ffe08..c208a62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,19 @@ node_modules/ package-lock.json +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db +nul + +# Old files +old/ +old-project/ +oramap-chart/ + diff --git a/README copy.md b/README copy.md deleted file mode 100644 index 5ca3466..0000000 --- a/README copy.md +++ /dev/null @@ -1,6 +0,0 @@ -# How to Run -``` -npm init -y -npm install express -node server.js -``` diff --git a/data/families.json b/data/families.json deleted file mode 100644 index f677668..0000000 --- a/data/families.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { "family": "Kafe (קאפח)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 }, - { "family": "Shiheb (שחב-שבח)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 }, - { "family": "Uzeyri (עזירי-עוזרי)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 }, - { "family": "Uzeyri (עזירי-עוזרי)", "city": "Manakhah (מנאכה)", "lat": 15.3019, "lng": 43.5983 }, - { "family": "Uzeyri (עזירי-עוזרי)", "city": "Dhamar (ד'מאר)", "lat": 14.5424, "lng": 44.4056 }, - { "family": "Salumi (סלומי-שלומי)", "city": "Al Kafla (אל קפלה)", "lat": 16.0240, "lng": 43.9790 }, - { "family": "Afgin (עפג'ין)", "city": "Sa'dah (צעדה)", "lat": 16.9402, "lng": 43.7639 }, - { "family": "Eraki (עראקי)", "city": "Sana'a (צנעא)", "lat": 15.3545, "lng": 44.2064 } - ] \ No newline at end of file diff --git a/frontend/nginx.conf b/frontend/nginx.conf index dfd8092..9a6d945 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -13,9 +13,19 @@ server { try_files $uri $uri/ /index.html; } - # API proxy to backend + # API proxy to backend service + # For Kubernetes: set BACKEND_HOST env var or use service name + # For Docker Compose: backend service name is 'backend' location /api/ { - proxy_pass http://backend:3000; + # In Kubernetes, this will be: oramap-backend:3000 + # In Docker Compose, this will be: backend:3000 + # Default to backend:3000 + set $backend_host backend; + if ($http_x_backend_host != "") { + set $backend_host $http_x_backend_host; + } + + proxy_pass http://$backend_host:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; diff --git a/oramap/Chart.yaml b/oramap/Chart.yaml index c7a98b5..8e91c0a 100644 --- a/oramap/Chart.yaml +++ b/oramap/Chart.yaml @@ -1,24 +1,11 @@ apiVersion: v2 name: oramap -description: A Helm chart for Kubernetes +description: Ora Map - Family Location Mapping Application (Microservices Architecture) -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. type: application -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 +# Chart version +version: 0.2.0 -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "1.16.0" +# Application version +appVersion: "1.0.0" diff --git a/oramap/templates/configmap.yaml b/oramap/templates/configmap.yaml new file mode 100644 index 0000000..ce380bc --- /dev/null +++ b/oramap/templates/configmap.yaml @@ -0,0 +1,45 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "oramap.fullname" . }}-nginx-config + labels: + app: {{ include "oramap.name" . }}-frontend + chart: {{ include "oramap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + default.conf: | + server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # Main location + location / { + try_files $uri $uri/ /index.html; + } + + # API proxy to backend service in Kubernetes + location /api/ { + proxy_pass http://{{ include "oramap.fullname" . }}-backend:{{ .Values.service.backend.port }}; + 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; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # Cache static assets + location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + } diff --git a/oramap/templates/deployment.yaml b/oramap/templates/deployment.yaml index e6eff7f..d8ee38a 100644 --- a/oramap/templates/deployment.yaml +++ b/oramap/templates/deployment.yaml @@ -1,38 +1,107 @@ +--- +# Backend Deployment apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "oramap.fullname" . }} + name: {{ include "oramap.fullname" . }}-backend labels: - app: {{ include "oramap.name" . }} + app: {{ include "oramap.name" . }}-backend chart: {{ include "oramap.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + component: backend spec: - replicas: {{ .Values.replicaCount }} + replicas: {{ .Values.backend.replicaCount }} selector: matchLabels: - app: {{ include "oramap.name" . }} + app: {{ include "oramap.name" . }}-backend release: {{ .Release.Name }} + component: backend template: metadata: labels: - app: {{ include "oramap.name" . }} + app: {{ include "oramap.name" . }}-backend release: {{ .Release.Name }} + component: backend spec: containers: - - name: {{ .Chart.Name }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} + - name: backend + image: "{{ .Values.backend.image.repository }}:{{ .Values.backend.image.tag }}" + imagePullPolicy: {{ .Values.backend.image.pullPolicy }} ports: - - containerPort: {{ .Values.containerPort }} + - containerPort: {{ .Values.backend.containerPort }} name: http + env: + - name: NODE_ENV + value: "production" + - name: PORT + value: "{{ .Values.backend.containerPort }}" + livenessProbe: + httpGet: + path: /api/health + port: http + initialDelaySeconds: 10 + periodSeconds: 30 + readinessProbe: + httpGet: + path: /api/health + port: http + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + {{- toYaml .Values.backend.resources | nindent 12 }} +--- +# Frontend Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "oramap.fullname" . }}-frontend + labels: + app: {{ include "oramap.name" . }}-frontend + chart: {{ include "oramap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + component: frontend +spec: + replicas: {{ .Values.frontend.replicaCount }} + selector: + matchLabels: + app: {{ include "oramap.name" . }}-frontend + release: {{ .Release.Name }} + component: frontend + template: + metadata: + labels: + app: {{ include "oramap.name" . }}-frontend + release: {{ .Release.Name }} + component: frontend + spec: + containers: + - name: frontend + image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag }}" + imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} + ports: + - containerPort: {{ .Values.frontend.containerPort }} + name: http + volumeMounts: + - name: nginx-config + mountPath: /etc/nginx/conf.d/default.conf + subPath: default.conf livenessProbe: httpGet: path: / port: http + initialDelaySeconds: 10 + periodSeconds: 30 readinessProbe: httpGet: path: / port: http + initialDelaySeconds: 5 + periodSeconds: 10 resources: - {{- toYaml .Values.resources | nindent 12 }} + {{- toYaml .Values.frontend.resources | nindent 12 }} + volumes: + - name: nginx-config + configMap: + name: {{ include "oramap.fullname" . }}-nginx-config diff --git a/oramap/templates/ingress.yaml b/oramap/templates/ingress.yaml index 04dabe8..47ad0d8 100644 --- a/oramap/templates/ingress.yaml +++ b/oramap/templates/ingress.yaml @@ -21,9 +21,9 @@ spec: pathType: {{ .pathType }} backend: service: - name: {{ include "oramap.fullname" $ }} + name: {{ include "oramap.fullname" $ }}-frontend port: - number: {{ $.Values.service.port }} + number: {{ $.Values.service.frontend.port }} {{- end }} {{- end }} {{- if .Values.ingress.tls }} diff --git a/oramap/templates/service.yaml b/oramap/templates/service.yaml index da296c8..f6da8d6 100644 --- a/oramap/templates/service.yaml +++ b/oramap/templates/service.yaml @@ -1,19 +1,46 @@ +--- +# Backend Service apiVersion: v1 kind: Service metadata: - name: {{ include "oramap.fullname" . }} + name: {{ include "oramap.fullname" . }}-backend labels: - app: {{ include "oramap.name" . }} + app: {{ include "oramap.name" . }}-backend chart: {{ include "oramap.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} + component: backend spec: type: {{ .Values.service.type }} ports: - - port: {{ .Values.service.port }} - targetPort: {{ .Values.containerPort }} + - port: {{ .Values.service.backend.port }} + targetPort: {{ .Values.service.backend.targetPort }} protocol: TCP name: http selector: - app: {{ include "oramap.name" . }} + app: {{ include "oramap.name" . }}-backend release: {{ .Release.Name }} + component: backend +--- +# Frontend Service +apiVersion: v1 +kind: Service +metadata: + name: {{ include "oramap.fullname" . }}-frontend + labels: + app: {{ include "oramap.name" . }}-frontend + chart: {{ include "oramap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + component: frontend +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.frontend.port }} + targetPort: {{ .Values.service.frontend.targetPort }} + protocol: TCP + name: http + selector: + app: {{ include "oramap.name" . }}-frontend + release: {{ .Release.Name }} + component: frontend diff --git a/oramap/values.yaml b/oramap/values.yaml index a110b9d..a171e88 100644 --- a/oramap/values.yaml +++ b/oramap/values.yaml @@ -1,15 +1,45 @@ replicaCount: 1 -image: - repository: harbor.dvirlabs.com/shay/oramap - tag: "1" - pullPolicy: IfNotPresent +# Backend API configuration +backend: + image: + repository: harbor.dvirlabs.com/my-apps/oramap-backend + tag: "latest" + pullPolicy: IfNotPresent + containerPort: 3000 + replicaCount: 1 + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi -containerPort: 3000 +# Frontend Nginx configuration +frontend: + image: + repository: harbor.dvirlabs.com/my-apps/oramap-frontend + tag: "latest" + pullPolicy: IfNotPresent + containerPort: 80 + replicaCount: 1 + resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 50m + memory: 64Mi service: type: ClusterIP - port: 80 + backend: + port: 3000 + targetPort: 3000 + frontend: + port: 80 + targetPort: 80 ingress: enabled: true diff --git a/public/index.html b/public/index.html deleted file mode 100644 index 86d16e9..0000000 --- a/public/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - 🗺️ Ora - - - - -
-

🗺️ Ora

- -
- -
-
-
- - - - - - \ No newline at end of file diff --git a/public/logo-shay.png b/public/logo-shay.png deleted file mode 100644 index 75c5947..0000000 Binary files a/public/logo-shay.png and /dev/null differ diff --git a/public/logo.png b/public/logo.png deleted file mode 100644 index b2425c2..0000000 Binary files a/public/logo.png and /dev/null differ diff --git a/public/script.js b/public/script.js deleted file mode 100644 index 2e213a5..0000000 --- a/public/script.js +++ /dev/null @@ -1,124 +0,0 @@ -let map = L.map('map').setView([15.5527, 48.5164], 6); - -// Define the two tile layers -const voyager = L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', { - attribution: '© OpenStreetMap contributors © CARTO', - subdomains: 'abcd', - maxZoom: 19 -}); - -const openStreetMap = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { - attribution: 'Map data © OpenStreetMap contributors', - maxZoom: 19 -}); - -// Add the default layer (Voyager) -voyager.addTo(map); - -// Group the layers for switching -const baseMaps = { - "English Map (CartoDB Voyager)": voyager, - "Original Map (OpenStreetMap)": openStreetMap -}; - -// Add the layer control to the map -L.control.layers(baseMaps).addTo(map); - -async function searchFamily() { - const familyName = document.getElementById('searchInput').value.trim(); - if (!familyName) { - alert('Please enter a family name.'); - return; - } - - try { - const response = await fetch(`/api/search?family=${encodeURIComponent(familyName)}`); - const familyResult = await response.json(); - - if (!familyResult.length) { - alert('No matching family found.'); - return; - } - - clearMarkers(); - - familyResult.forEach(record => { - L.marker([record.lat, record.lng]).addTo(map) - .bindPopup(`${record.family}
City: ${record.city}`) - .openPopup(); - }); - - const first = familyResult[0]; - map.setView([first.lat, first.lng], 7); - - } catch (error) { - console.error('Search error:', error); - alert('Something went wrong while searching. Please try again later.'); - } -} - -function clearMarkers() { - map.eachLayer(layer => { - if (layer instanceof L.Marker) { - map.removeLayer(layer); - } - }); -} - -const familyNames = [ - "Kafe (קאפח)", "Shiheb (שחב-שבח)", "Eraki (עראקי)", "Salumi (סלומי-שלומי)", - "Afgin (עפג'ין)", "Uzeyri (עזירי-עוזרי)" - // Add more families here if you like - ]; - - // Initialize Fuse.js - const fuse = new Fuse(familyNames, { - includeScore: true, - threshold: 0.4 // Lower = stricter matching - }); - -const searchInput = document.getElementById('searchInput'); -const suggestionsBox = document.createElement('div'); -suggestionsBox.classList.add('suggestions'); -searchInput.parentNode.style.position = 'relative'; // Make parent relative -searchInput.parentNode.appendChild(suggestionsBox); - -searchInput.addEventListener('input', () => { - const value = searchInput.value.trim(); - suggestionsBox.innerHTML = ''; - - if (!value) return; - - const results = fuse.search(value); - - results.forEach(result => { - const option = document.createElement('div'); - option.textContent = result.item; - option.onclick = () => { - searchInput.value = result.item; - suggestionsBox.innerHTML = ''; - }; - suggestionsBox.appendChild(option); - }); -}); - -L.control.logo = function (opts) { - return new L.Control.Logo(opts); - }; - -L.Control.Logo = L.Control.extend({ - onAdd: function () { - const div = L.DomUtil.create('div', 'custom-logo'); - div.innerHTML = ` - Logo - Shevach - `; - return div; - }, - - onRemove: function () { - // Nothing to clean up - } -}); - -L.control.logo({ position: 'bottomleft' }).addTo(map); \ No newline at end of file diff --git a/public/style.css b/public/style.css deleted file mode 100644 index 12ddc35..0000000 --- a/public/style.css +++ /dev/null @@ -1,98 +0,0 @@ -/* Reset some basic styles */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; - } - - body { - font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; - background: #f4f4f4; - display: flex; - flex-direction: column; - min-height: 100vh; - } - - /* Header styles */ - header { - background-color: #2c3e50; - padding: 20px; - text-align: center; - color: white; - } - - h1 { - margin-bottom: 10px; - } - - .search-bar { - margin-top: 10px; - } - - .search-bar input { - padding: 10px; - width: 250px; - border: none; - border-radius: 5px; - margin-right: 8px; - } - - .search-bar button { - padding: 10px 15px; - border: none; - border-radius: 5px; - background-color: #3498db; - color: white; - cursor: pointer; - font-weight: bold; - } - - .suggestions { - background: #363251; - border: 1px solid #ccc; - position: absolute; - top: 110%; /* Just below the input */ - left: 48%; - transform: translateX(-50%); - max-width: fit-content; - min-width: 200px; /* Optional: minimum size */ - max-height: 200px; - overflow-y: auto; - z-index: 1000; - box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1); - border-radius: 8px; - transition: all 0.2s ease-in-out; - } - - .suggestions div { - padding: 10px; - cursor: pointer; - } - - .suggestions div:hover { - background-color: #95a1a8; - } - - .custom-logo { - background: rgba(255, 255, 255, 0.9); - padding: 6px 10px; - border-radius: 8px; - box-shadow: 0 0 8px rgba(0, 0, 0, 0.1); - display: flex; - align-items: center; - font-family: sans-serif; - } - - /* Map container */ - #map { - flex-grow: 1; - height: 80vh; - width: 100%; - } - - /* Main container */ - main { - flex: 1; - display: flex; - flex-direction: column; - } \ No newline at end of file diff --git a/run_ora_map.sh b/run_ora_map.sh deleted file mode 100644 index 428c8a6..0000000 --- a/run_ora_map.sh +++ /dev/null @@ -1,3 +0,0 @@ -npm init -y -npm install express -node server.js diff --git a/server.js b/server.js deleted file mode 100644 index 2e8b56a..0000000 --- a/server.js +++ /dev/null @@ -1,19 +0,0 @@ -const express = require('express'); -const app = express(); -const families = require('./data/families.json'); - -app.use(express.static('public')); - -app.get('/search', (req, res) => { - const query = req.query.family?.toLowerCase(); - if (!query) { - return res.json([]); - } - const matches = families.filter(fam => fam.family.toLowerCase().includes(query)); - res.json(matches); -}); - -const port = 3000; -app.listen(port, () => { - console.log(`Server running at http://localhost:${port}`); -}); \ No newline at end of file