@gokiteam/goki-dev 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,38 @@
1
+ FROM node:20-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ # Install Java JRE 21 for Firebase Emulator + build tools for better-sqlite3 + Docker CLI + PostgreSQL client
6
+ RUN apk add --no-cache openjdk21-jre bash python3 make g++ docker-cli postgresql-client
7
+
8
+ # Install Firebase CLI globally for Firestore emulator
9
+ RUN npm install -g firebase-tools
10
+
11
+ # Copy package files and npm config
12
+ COPY package*.json ./
13
+
14
+ # Build arg for npm authentication
15
+ ARG NPM_TOKEN
16
+ ENV NPM_TOKEN=${NPM_TOKEN}
17
+ COPY .npmrc ./
18
+
19
+ # Install dependencies (including optional native deps like better-sqlite3)
20
+ RUN npm install --omit=dev --include=optional
21
+
22
+ # Copy source code
23
+ COPY src/ ./src/
24
+ COPY config.development ./
25
+ COPY config.test ./
26
+
27
+ # Copy Firebase configuration
28
+ COPY firebase.json ./
29
+ COPY firestore.rules ./
30
+
31
+ # Create data and logs directories
32
+ RUN mkdir -p /app/data /app/logs /app/data/firestore
33
+
34
+ # Expose ports
35
+ EXPOSE 9000 8085 8087 8883 8080
36
+
37
+ # Start server directly (env vars set via docker-compose)
38
+ CMD ["node", "src/Server.js"]
package/Dockerfile.dev ADDED
@@ -0,0 +1,38 @@
1
+ FROM node:20-alpine
2
+
3
+ WORKDIR /app
4
+
5
+ # Install Java JRE 21 for Firebase Emulator + build tools for better-sqlite3 + PostgreSQL client
6
+ RUN apk add --no-cache openjdk21-jre bash python3 make g++ postgresql-client
7
+
8
+ # Install Firebase CLI globally for Firestore emulator
9
+ RUN npm install -g firebase-tools
10
+
11
+ # Copy package files and npm config
12
+ COPY package*.json ./
13
+
14
+ # Build arg for npm authentication
15
+ ARG NPM_TOKEN
16
+ ENV NPM_TOKEN=${NPM_TOKEN}
17
+ COPY .npmrc ./
18
+
19
+ # Install ALL dependencies (including dev for watch mode)
20
+ RUN npm install
21
+
22
+ # Install nodemon for reliable file watching in Docker (fs.watch doesn't work with bind mounts)
23
+ RUN npm install -g nodemon
24
+
25
+ # Copy config files
26
+ COPY config.development ./
27
+ COPY config.test ./
28
+ COPY firebase.json ./
29
+ COPY firestore.rules ./
30
+
31
+ # Create data and logs directories
32
+ RUN mkdir -p /app/data /app/logs /app/data/firestore
33
+
34
+ # Expose ports
35
+ EXPOSE 9000 8085 8087 8883 8080
36
+
37
+ # Start server with watch mode using nodemon (polling for Docker bind mount compatibility)
38
+ CMD ["nodemon", "--watch", "src", "--ext", "js,json", "--legacy-watch", "--polling-interval", "1000", "src/Server.js"]
@@ -0,0 +1,37 @@
1
+ # Build stage
2
+ FROM node:20-alpine AS build
3
+
4
+ WORKDIR /app
5
+
6
+ # Copy UI package files
7
+ COPY ui/package*.json ./ui/
8
+
9
+ # Install UI dependencies
10
+ WORKDIR /app/ui
11
+ RUN npm ci
12
+
13
+ # Copy UI source files
14
+ COPY ui/ ./
15
+
16
+ # Build the React app
17
+ # API URL will be injected at runtime via environment variable
18
+ RUN npm run build
19
+
20
+ # Production stage
21
+ FROM nginx:1.25-alpine
22
+
23
+ # Copy nginx configuration
24
+ COPY nginx.conf /etc/nginx/conf.d/default.conf
25
+
26
+ # Copy built files from build stage
27
+ COPY --from=build /app/ui/build /usr/share/nginx/html
28
+
29
+ # Add healthcheck
30
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
31
+ CMD wget --quiet --tries=1 --spider http://127.0.0.1/health || exit 1
32
+
33
+ # Expose port
34
+ EXPOSE 80
35
+
36
+ # Start nginx
37
+ CMD ["nginx", "-g", "daemon off;"]
@@ -1,13 +1,12 @@
1
1
  import { execa } from 'execa'
2
2
  import fs from 'fs'
3
+ import os from 'os'
3
4
  import path from 'path'
4
- import { fileURLToPath } from 'url'
5
5
  import { Logger } from './Logger.js'
6
6
 
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url))
8
7
  const DEV_TOOLS_API = 'http://localhost:9000'
9
8
  const NGROK_API = 'http://localhost:4040'
10
- const DATA_DIR = path.resolve(__dirname, '..', 'data')
9
+ const DATA_DIR = path.join(os.homedir(), '.goki-dev', 'data')
11
10
  const PID_FILE = path.join(DATA_DIR, 'ngrok.pid')
12
11
  const STATE_FILE = path.join(DATA_DIR, 'ngrok.json')
13
12
 
@@ -17,7 +17,6 @@ SHADOW_SUBSCRIPTION_CHECK_INTERVAL_MS=5000
17
17
  FIRESTORE_PROJECT_ID=goki-dev-local
18
18
 
19
19
  # Storage
20
- DATA_DIR=./data
21
20
  AUTO_FLUSH_INTERVAL_MS=5000
22
21
 
23
22
  # Redis (for app data)
@@ -0,0 +1,81 @@
1
+ # App services (dev-tools backend + UI)
2
+ # Requires shared services running first: docker compose -f docker-compose.services.yml up -d
3
+ # Then start: docker compose -f docker-compose.dev.yml up -d
4
+
5
+ services:
6
+ backend:
7
+ image: goki-dev-tools-backend
8
+ build:
9
+ context: .
10
+ dockerfile: Dockerfile.dev
11
+ args:
12
+ NPM_TOKEN: ${NPM_TOKEN}
13
+ container_name: goki-dev-tools-backend
14
+ ports:
15
+ - "9000:9000" # Backend API
16
+ - "8087:8087" # Cloud Logging Emulator
17
+ - "8883:8883" # MQTT Broker
18
+ environment:
19
+ - NODE_ENV=development
20
+ - WEB_UI_PORT=9000
21
+ # Shared services (use container names for cross-compose networking)
22
+ - POSTGRES_HOST=goki-postgres
23
+ - POSTGRES_PORT=5432
24
+ - POSTGRES_USER=postgres
25
+ - POSTGRES_PASSWORD=postgres
26
+ - POSTGRES_DATABASE=device_native
27
+ - REDIS_HOST=goki-redis
28
+ - REDIS_PORT=6379
29
+ - REDIS_LOGS_HOST=goki-redis-logs
30
+ - REDIS_LOGS_PORT=6380
31
+ - PUBSUB_EMULATOR_HOST=goki-pubsub-emulator:8085
32
+ - FIRESTORE_EMULATOR_HOST=goki-firestore-emulator:8080
33
+ - FIRESTORE_PROJECT_ID=tipi-development
34
+ - FIRESTORE_PROJECT_IDS=tipi-development,goki-dev-local
35
+ # App-specific config
36
+ - LOGGING_PORT=8087
37
+ - MQTT_PORT=8883
38
+ - DATA_DIR=/app/data
39
+ - AUTO_FLUSH_INTERVAL_MS=5000
40
+ - LOG_LEVEL=info
41
+ - UI_DEV_SERVER=http://goki-dev-tools-frontend:9001
42
+ - CHOKIDAR_USEPOLLING=true
43
+ - HOST_PROJECT_DIR=${HOST_PROJECT_DIR:-${PWD}}
44
+ volumes:
45
+ - ./src:/app/src:ro
46
+ - ./docs:/app/docs:ro
47
+ - ~/.goki-dev/data:/app/data
48
+ - ./logs:/app/logs
49
+ - /var/run/docker.sock:/var/run/docker.sock:ro
50
+ depends_on:
51
+ - frontend
52
+ networks:
53
+ - goki-network
54
+ restart: unless-stopped
55
+
56
+ frontend:
57
+ image: goki-dev-tools-frontend
58
+ build:
59
+ context: ./ui
60
+ dockerfile: Dockerfile.dev
61
+ container_name: goki-dev-tools-frontend
62
+ ports:
63
+ - "9001:9001" # React dev server
64
+ environment:
65
+ - PORT=9001
66
+ - CHOKIDAR_USEPOLLING=true
67
+ - WATCHPACK_POLLING=true
68
+ - WDS_SOCKET_PORT=9001
69
+ volumes:
70
+ - ./ui/src:/app/src
71
+ - ./ui/public:/app/public
72
+ - ./ui/tailwind.config.js:/app/tailwind.config.js:ro
73
+ - ./ui/postcss.config.js:/app/postcss.config.js:ro
74
+ networks:
75
+ - goki-network
76
+ restart: unless-stopped
77
+
78
+
79
+ networks:
80
+ goki-network:
81
+ external: true
@@ -0,0 +1,186 @@
1
+ # Shared infrastructure services (PostgreSQL, Redis, Emulators)
2
+ # Start these first: docker compose -f docker-compose.services.yml up -d
3
+ # Then start app services: docker compose -f docker-compose.dev.yml up -d
4
+
5
+ services:
6
+ postgres:
7
+ image: postgres:15-alpine
8
+ container_name: goki-postgres
9
+ environment:
10
+ POSTGRES_USER: postgres
11
+ POSTGRES_PASSWORD: postgres
12
+ ports:
13
+ - "5432:5432"
14
+ volumes:
15
+ - postgres-data:/var/lib/postgresql/data
16
+ networks:
17
+ - goki-network
18
+ restart: unless-stopped
19
+ labels:
20
+ - "goki.service=postgres"
21
+ healthcheck:
22
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
23
+ interval: 5s
24
+ timeout: 5s
25
+ retries: 5
26
+ profiles:
27
+ - postgres
28
+
29
+ redis:
30
+ image: redis:7-alpine
31
+ container_name: goki-redis
32
+ ports:
33
+ - "6379:6379"
34
+ volumes:
35
+ - redis-data:/data
36
+ networks:
37
+ - goki-network
38
+ restart: unless-stopped
39
+ labels:
40
+ - "goki.service=redis"
41
+ healthcheck:
42
+ test: ["CMD", "redis-cli", "ping"]
43
+ interval: 5s
44
+ timeout: 5s
45
+ retries: 5
46
+
47
+ redis-logs:
48
+ image: redis:7-alpine
49
+ container_name: goki-redis-logs
50
+ command: redis-server --port 6380 --maxmemory 256mb --maxmemory-policy allkeys-lru
51
+ ports:
52
+ - "6380:6380"
53
+ volumes:
54
+ - redis-logs-data:/data
55
+ networks:
56
+ - goki-network
57
+ restart: unless-stopped
58
+ labels:
59
+ - "goki.service=redis-logs"
60
+ healthcheck:
61
+ test: ["CMD", "redis-cli", "-p", "6380", "ping"]
62
+ interval: 5s
63
+ timeout: 5s
64
+ retries: 5
65
+ profiles:
66
+ - redis-logs
67
+
68
+ pubsub-emulator:
69
+ image: gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators
70
+ container_name: goki-pubsub-emulator
71
+ command: gcloud beta emulators pubsub start --host-port=0.0.0.0:8085 --project=tipi-development
72
+ ports:
73
+ - "8085:8085"
74
+ networks:
75
+ - goki-network
76
+ restart: unless-stopped
77
+ labels:
78
+ - "goki.service=pubsub-emulator"
79
+ healthcheck:
80
+ test: ["CMD-SHELL", "curl -sf http://localhost:8085/v1/projects/tipi-development/topics || exit 1"]
81
+ interval: 5s
82
+ timeout: 5s
83
+ retries: 10
84
+ start_period: 10s
85
+
86
+ firestore-emulator:
87
+ image: gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators
88
+ container_name: goki-firestore-emulator
89
+ entrypoint: /bin/bash
90
+ command:
91
+ - -c
92
+ - |
93
+ IMPORT_FILE=$$(find /data/firestore-export -name '*.overall_export_metadata' 2>/dev/null | head -1)
94
+ if [ -n "$$IMPORT_FILE" ]; then
95
+ echo "Importing Firestore data from $$IMPORT_FILE"
96
+ exec gcloud emulators firestore start --host-port=0.0.0.0:8080 --project=goki-dev-local --export-on-exit=/data/firestore-export --import-data="$$IMPORT_FILE"
97
+ else
98
+ echo "No previous export found, starting fresh"
99
+ exec gcloud emulators firestore start --host-port=0.0.0.0:8080 --project=goki-dev-local --export-on-exit=/data/firestore-export
100
+ fi
101
+ ports:
102
+ - "8080:8080"
103
+ volumes:
104
+ - firestore-data:/data
105
+ networks:
106
+ - goki-network
107
+ restart: unless-stopped
108
+ labels:
109
+ - "goki.service=firestore-emulator"
110
+ healthcheck:
111
+ test: ["CMD-SHELL", "curl -sf http://localhost:8080/ || exit 1"]
112
+ interval: 5s
113
+ timeout: 5s
114
+ retries: 10
115
+ start_period: 10s
116
+ profiles:
117
+ - firestore
118
+
119
+ elasticsearch:
120
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
121
+ container_name: goki-elasticsearch
122
+ environment:
123
+ - discovery.type=single-node
124
+ - xpack.security.enabled=false
125
+ - ES_JAVA_OPTS=-Xms1g -Xmx1g
126
+ ports:
127
+ - "9200:9200"
128
+ volumes:
129
+ - elasticsearch-data:/usr/share/elasticsearch/data
130
+ networks:
131
+ - goki-network
132
+ restart: unless-stopped
133
+ labels:
134
+ - "goki.service=elasticsearch"
135
+ deploy:
136
+ resources:
137
+ limits:
138
+ memory: 2g
139
+ healthcheck:
140
+ test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health || exit 1"]
141
+ interval: 10s
142
+ timeout: 5s
143
+ retries: 10
144
+ start_period: 30s
145
+ profiles:
146
+ - elasticsearch
147
+
148
+ kibana:
149
+ image: docker.elastic.co/kibana/kibana:8.12.0
150
+ container_name: goki-kibana
151
+ environment:
152
+ - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
153
+ ports:
154
+ - "5601:5601"
155
+ depends_on:
156
+ elasticsearch:
157
+ condition: service_healthy
158
+ networks:
159
+ - goki-network
160
+ restart: unless-stopped
161
+ labels:
162
+ - "goki.service=kibana"
163
+ deploy:
164
+ resources:
165
+ limits:
166
+ memory: 1g
167
+ healthcheck:
168
+ test: ["CMD-SHELL", "curl -sf http://localhost:5601/api/status || exit 1"]
169
+ interval: 10s
170
+ timeout: 5s
171
+ retries: 10
172
+ start_period: 60s
173
+ profiles:
174
+ - kibana
175
+
176
+ networks:
177
+ goki-network:
178
+ name: goki-network
179
+ driver: bridge
180
+
181
+ volumes:
182
+ postgres-data:
183
+ redis-data:
184
+ redis-logs-data:
185
+ firestore-data:
186
+ elasticsearch-data:
@@ -0,0 +1,233 @@
1
+ services:
2
+ pubsub-emulator:
3
+ image: gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators
4
+ container_name: goki-pubsub-emulator
5
+ command: gcloud beta emulators pubsub start --host-port=0.0.0.0:8085 --project=tipi-development
6
+ ports:
7
+ - "8085:8085"
8
+ networks:
9
+ - goki-network
10
+ restart: unless-stopped
11
+ labels:
12
+ - "goki.service=pubsub-emulator"
13
+ healthcheck:
14
+ test: ["CMD", "curl", "-f", "http://localhost:8085"]
15
+ interval: 5s
16
+ timeout: 5s
17
+ retries: 10
18
+ start_period: 10s
19
+
20
+ firestore-emulator:
21
+ image: gcr.io/google.com/cloudsdktool/google-cloud-cli:emulators
22
+ container_name: goki-firestore-emulator
23
+ entrypoint: /bin/bash
24
+ command:
25
+ - -c
26
+ - |
27
+ IMPORT_FILE=$$(find /data/firestore-export -name '*.overall_export_metadata' 2>/dev/null | head -1)
28
+ if [ -n "$$IMPORT_FILE" ]; then
29
+ echo "Importing Firestore data from $$IMPORT_FILE"
30
+ exec gcloud emulators firestore start --host-port=0.0.0.0:8081 --project=goki-dev-local --export-on-exit=/data/firestore-export --import-data="$$IMPORT_FILE"
31
+ else
32
+ echo "No previous export found, starting fresh"
33
+ exec gcloud emulators firestore start --host-port=0.0.0.0:8081 --project=goki-dev-local --export-on-exit=/data/firestore-export
34
+ fi
35
+ ports:
36
+ - "8081:8081"
37
+ volumes:
38
+ - firestore-data:/data
39
+ networks:
40
+ - goki-network
41
+ restart: unless-stopped
42
+ labels:
43
+ - "goki.service=firestore-emulator"
44
+ healthcheck:
45
+ test: ["CMD-SHELL", "curl -sf http://localhost:8081 || exit 1"]
46
+ interval: 10s
47
+ timeout: 10s
48
+ retries: 12
49
+ start_period: 60s
50
+ profiles:
51
+ - firestore
52
+
53
+ dev-tools-backend:
54
+ build:
55
+ context: .
56
+ dockerfile: Dockerfile.backend
57
+ args:
58
+ NPM_TOKEN: ${NPM_TOKEN}
59
+ container_name: goki-dev-tools-backend
60
+ ports:
61
+ - "9000:9000" # Backend API
62
+ - "8086:8086" # AWS IoT Core HTTPS API
63
+ - "8087:8087" # Cloud Logging Emulator
64
+ - "8883:8883" # MQTT Broker
65
+ labels:
66
+ - "goki.service=dev-tools-backend"
67
+ environment:
68
+ - NODE_ENV=production
69
+ - WEB_UI_PORT=9000
70
+ - PUBSUB_EMULATOR_HOST=pubsub-emulator:8085
71
+ - PUBSUB_PROJECT_ID=tipi-development
72
+ - SHADOW_POLL_INTERVAL_MS=200
73
+ - SHADOW_SUBSCRIPTION_CHECK_INTERVAL_MS=5000
74
+ - LOGGING_PORT=8087
75
+ - MQTT_PORT=8883
76
+ - AWS_IOT_PORT=8086
77
+ - FIRESTORE_EMULATOR_HOST=goki-firestore-emulator:8080
78
+ - FIRESTORE_PORT=8080
79
+ - FIRESTORE_PROJECT_ID=tipi-development
80
+ - DATA_DIR=/app/data
81
+ - AUTO_FLUSH_INTERVAL_MS=5000
82
+ - REDIS_HOST=redis
83
+ - REDIS_PORT=6379
84
+ - POSTGRES_HOST=postgres
85
+ - POSTGRES_PORT=5432
86
+ - POSTGRES_USER=postgres
87
+ - POSTGRES_PASSWORD=postgres
88
+ - LOG_LEVEL=info
89
+ # App Gateway config (use container names)
90
+ - APP_GATEWAY_PROPERTY_ID=550e8400-e29b-41d4-a716-446655440000
91
+ - APP_GATEWAY_DEVICE_NATIVE_URL=http://device-native-app:3000
92
+ - APP_GATEWAY_DEVICE_SIMULATOR_URL=http://device-simulator-app:3000
93
+ - APP_GATEWAY_SCAN_INTERVAL_SECONDS=30
94
+ - APP_GATEWAY_AUTO_START=true
95
+ volumes:
96
+ - ~/.goki-dev/data:/app/data
97
+ - ./logs:/app/logs
98
+ - /var/run/docker.sock:/var/run/docker.sock
99
+ depends_on:
100
+ pubsub-emulator:
101
+ condition: service_healthy
102
+ redis:
103
+ condition: service_started
104
+ # Note: firestore and postgres are optional (have profiles)
105
+ # App should gracefully handle missing connections
106
+ networks:
107
+ - goki-network
108
+ restart: unless-stopped
109
+
110
+ dev-tools-frontend:
111
+ build:
112
+ context: .
113
+ dockerfile: Dockerfile.frontend
114
+ container_name: goki-dev-tools-frontend
115
+ ports:
116
+ - "9001:80" # Frontend UI
117
+ labels:
118
+ - "goki.service=dev-tools-frontend"
119
+ depends_on:
120
+ - dev-tools-backend
121
+ networks:
122
+ - goki-network
123
+ restart: unless-stopped
124
+ healthcheck:
125
+ test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://127.0.0.1/health || exit 1"]
126
+ interval: 30s
127
+ timeout: 3s
128
+ start_period: 10s
129
+ retries: 3
130
+
131
+ redis:
132
+ image: redis:7-alpine
133
+ container_name: goki-redis
134
+ ports:
135
+ - "6379:6379"
136
+ volumes:
137
+ - redis-data:/data
138
+ networks:
139
+ - goki-network
140
+ restart: unless-stopped
141
+ labels:
142
+ - "goki.service=redis"
143
+
144
+ postgres:
145
+ image: postgres:15-alpine
146
+ container_name: goki-postgres
147
+ environment:
148
+ POSTGRES_USER: postgres
149
+ POSTGRES_PASSWORD: postgres
150
+ ports:
151
+ - "5432:5432"
152
+ volumes:
153
+ - postgres-data:/var/lib/postgresql/data
154
+ networks:
155
+ - goki-network
156
+ restart: unless-stopped
157
+ labels:
158
+ - "goki.service=postgres"
159
+ healthcheck:
160
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
161
+ interval: 5s
162
+ timeout: 5s
163
+ retries: 5
164
+ profiles:
165
+ - postgres
166
+
167
+ elasticsearch:
168
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
169
+ container_name: goki-elasticsearch
170
+ environment:
171
+ - discovery.type=single-node
172
+ - xpack.security.enabled=false
173
+ - ES_JAVA_OPTS=-Xms1g -Xmx1g
174
+ ports:
175
+ - "9200:9200"
176
+ volumes:
177
+ - elasticsearch-data:/usr/share/elasticsearch/data
178
+ networks:
179
+ - goki-network
180
+ restart: unless-stopped
181
+ labels:
182
+ - "goki.service=elasticsearch"
183
+ deploy:
184
+ resources:
185
+ limits:
186
+ memory: 2g
187
+ healthcheck:
188
+ test: ["CMD-SHELL", "curl -sf http://localhost:9200/_cluster/health || exit 1"]
189
+ interval: 10s
190
+ timeout: 5s
191
+ retries: 10
192
+ start_period: 30s
193
+ profiles:
194
+ - elasticsearch
195
+
196
+ kibana:
197
+ image: docker.elastic.co/kibana/kibana:8.12.0
198
+ container_name: goki-kibana
199
+ environment:
200
+ - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
201
+ ports:
202
+ - "5601:5601"
203
+ depends_on:
204
+ elasticsearch:
205
+ condition: service_healthy
206
+ networks:
207
+ - goki-network
208
+ restart: unless-stopped
209
+ labels:
210
+ - "goki.service=kibana"
211
+ deploy:
212
+ resources:
213
+ limits:
214
+ memory: 1g
215
+ healthcheck:
216
+ test: ["CMD-SHELL", "curl -sf http://localhost:5601/api/status || exit 1"]
217
+ interval: 10s
218
+ timeout: 5s
219
+ retries: 10
220
+ start_period: 60s
221
+ profiles:
222
+ - kibana
223
+
224
+ networks:
225
+ goki-network:
226
+ name: goki-network
227
+ driver: bridge
228
+
229
+ volumes:
230
+ redis-data:
231
+ postgres-data:
232
+ firestore-data:
233
+ elasticsearch-data:
package/nginx.conf ADDED
@@ -0,0 +1,41 @@
1
+ server {
2
+ listen 80;
3
+ server_name localhost;
4
+ root /usr/share/nginx/html;
5
+ index index.html;
6
+
7
+ # Gzip compression
8
+ gzip on;
9
+ gzip_vary on;
10
+ gzip_min_length 1024;
11
+ gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript;
12
+
13
+ # Security headers
14
+ add_header X-Frame-Options "SAMEORIGIN" always;
15
+ add_header X-Content-Type-Options "nosniff" always;
16
+ add_header X-XSS-Protection "1; mode=block" always;
17
+
18
+ # Serve static files
19
+ location / {
20
+ try_files $uri $uri/ /index.html;
21
+ }
22
+
23
+ # Cache static assets
24
+ location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
25
+ expires 1y;
26
+ add_header Cache-Control "public, immutable";
27
+ }
28
+
29
+ # Don't cache index.html
30
+ location = /index.html {
31
+ add_header Cache-Control "no-store, no-cache, must-revalidate";
32
+ expires 0;
33
+ }
34
+
35
+ # Health check endpoint
36
+ location /health {
37
+ access_log off;
38
+ return 200 "healthy\n";
39
+ add_header Content-Type text/plain;
40
+ }
41
+ }