From a837ae06bd34043ab107fb8f8421694abc59e52b Mon Sep 17 00:00:00 2001
From: Fabio Manganiello <fabio@manganiello.tech>
Date: Fri, 7 Mar 2025 00:19:45 +0100
Subject: [PATCH] Added Docker support.

---
 .env.example       |  2 +-
 .gitignore         |  1 +
 Dockerfile         | 65 ++++++++++++++++++++++++++++++++++++++++++++++
 README.md          | 35 +++++++++++++++----------
 docker-compose.yml | 43 ++++++++++++++++++++++++++++++
 5 files changed, 132 insertions(+), 14 deletions(-)
 create mode 100644 Dockerfile
 create mode 100644 docker-compose.yml

diff --git a/.env.example b/.env.example
index bb5a696..4a211c9 100644
--- a/.env.example
+++ b/.env.example
@@ -10,7 +10,7 @@ BACKEND_PORT=3000
 
 # Application database URL (required)
 # Postgres:
-DB_URL=postgres://user:password@host:port/dbname
+DB_URL=postgres://gpstracker:gpstracker@db:5432/gpstracker
 # SQLite:
 # DB_URL=sqlite:///path/to/app.db
 
diff --git a/.gitignore b/.gitignore
index 7410ef1..b0cc64c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,3 +30,4 @@ coverage
 *.db
 *.sqlite
 *.sqlite3
+data/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..abdfde9
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,65 @@
+# Build image
+FROM node:23-alpine AS build
+
+WORKDIR /app
+
+# Copy backend source files
+COPY LICENSE \
+     README.md \
+     package.json \
+     package-lock.json \
+     tsconfig.json \
+     Makefile \
+     ./
+
+COPY src ./src
+
+# Copy frontend source files
+RUN mkdir -p ./frontend
+COPY frontend/package.json \
+     frontend/package-lock.json \
+     frontend/tsconfig.json \
+     frontend/tsconfig.app.json \
+     frontend/tsconfig.node.json \
+     frontend/vite.config.ts \
+     frontend/env.d.ts \
+     frontend/index.html \
+     frontend/Makefile \
+     ./frontend/
+
+COPY frontend/src ./frontend/src
+COPY frontend/public ./frontend/public
+
+# Install system dependencies
+RUN apk add --no-cache typescript make
+
+# Build all
+RUN make
+
+# Web image
+FROM node:23-alpine AS web
+
+WORKDIR /app
+
+# Copy built files
+COPY --from=build \
+     /app/package.json \
+     /app/LICENSE \
+     /app/README.md \
+     ./
+
+COPY --from=build /app/dist ./dist
+COPY --from=build /app/node_modules ./node_modules
+
+# Copy frontend built files
+COPY --from=build /app/frontend/dist ./frontend/dist
+COPY --from=build /app/frontend/node_modules ./frontend/node_modules
+COPY --from=build /app/frontend/public ./frontend/public
+COPY --from=build \
+     /app/frontend/package.json \
+     /app/frontend/package-lock.json \
+     /app/frontend/index.html \
+     /app/frontend/
+
+# Run the app
+CMD ["npm", "run", "start"]
diff --git a/README.md b/README.md
index 86373c7..b506b66 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,26 @@ GPSTracker is a simple Webapp that consists of:
   - [[*TODO*]] Can ingest GPS data points from HTTP, MQTT, Websocket or Kafka.
 - A frontend to display GPS data points and provides advanced filtering.
 
-## Building the application
+![Screenshot of GPSTracker](https://static.platypush.tech/screenshots/gpstracker_screenshot.png)
+
+## Configuration
+
+```
+cp .env.example .env
+```
+
+See [the provided `.env.example`](./.env.example) for a reference.
+
+## Docker installation
+
+```sh
+docker compose up
+```
+
+## Local installation
+
+
+### Build
 
 Requirements:
 
@@ -34,23 +53,13 @@ make backend
 make frontend
 ```
 
-## Configuration
-
-See [`.env.example`](./.env.example) for a reference. Copy it to `.env` and modify it accordingly.
-
-## Running the application
-
-### Local installation
+### Run
 
 ```sh
 npm run start
 ```
 
-### Docker
-
-[[*TODO*]]
-
-## Project Setup
+## Development
 
 ### Compile and Hot-Reload for Development
 
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..a863c4f
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,43 @@
+services:
+  app:
+    build:
+      context: .
+      dockerfile: Dockerfile
+    env_file:
+      - ./.env
+    environment:
+      # Needed to make sure that the backend port can be exposed
+      BACKEND_ADDRESS: 0.0.0.0
+    ports:
+      - 3000:3000
+    depends_on:
+      db:
+        condition: service_healthy
+    healthcheck:
+      # If you change the backend port, remember to also change this URL
+      test: curl -s 'http://localhost:3000' >/dev/null
+      interval: 10s
+      timeout: 5s
+      retries: 5
+    restart: unless-stopped
+
+  db:
+    image: postgres:17-alpine
+    environment:
+      # These should match the settings reported in your DB_URL env variable
+      - POSTGRES_USER=gpstracker
+      - POSTGRES_PASSWORD=gpstracker
+      - POSTGRES_DB=gpstracker
+    volumes:
+      - data:/var/lib/postgresql/data/
+    expose:
+      - 5432
+    healthcheck:
+      test: pg_isready -U gpstracker
+      interval: 2s
+      timeout: 5s
+      retries: 10
+    restart: unless-stopped
+
+volumes:
+  data: