From 60392bd242a9b449856a9dcf4b925799081065fd Mon Sep 17 00:00:00 2001 From: Shatakshi Tiwari Date: Wed, 14 Oct 2026 15:10:15 +0530 Subject: [PATCH] feat: containerize frontend for compose deployment Signed-off-by: Shatakshi Tiwari --- .dockerignore | 5 ++ .env.example | 24 ++++----- .gitignore | 2 +- Dockerfile | 24 +++++++++ README.md | 95 ++++++++++++++++++++++++++-------- docker-compose.yml | 71 +++++++++++++++++++++++++ docs/licensedb-compose.service | 21 ++++++++ nginx/default.conf | 23 ++++++++ 8 files changed, 230 insertions(+), 35 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 docs/licensedb-compose.service create mode 100644 nginx/default.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..8675725 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +build +.env +.env.local +.git \ No newline at end of file diff --git a/.env.example b/.env.example index 5bb1c52..1dc559c 100644 --- a/.env.example +++ b/.env.example @@ -2,17 +2,17 @@ # SPDX-FileCopyrightText: © 2025 Siemens AG # SPDX-FileContributor: Dearsh Oberoi -REACT_APP_BASE_URL='http://localhost:5000/api/v1' -REACT_APP_DOMAIN_SUBDIRECTORY='' -PUBLIC_URL='http:localhost:3000' +# Vite build configuration +VITE_BASE_URL=/api/v1 +VITE_DOMAIN_SUBDIRECTORY= -# possible values are oidc or password. If password, ui for username-password -# login will be shown, otherwise, ui for oidc will be shown. -# if unset or some other value, username-password login flow will be shown by default -REACT_APP_PROVIDER='password' +# Full-stack Docker Compose configuration +# The backend repository must be checked out next to this repository. +LICENSEDB_BACKEND_CONTEXT=../LicenseDb +LICENSEDB_UI_PORT=8081 -#OIDC -REACT_APP_CLIENT_ID='client-id' -REACT_APP_AUTH_URL='provider authorization url' -REACT_APP_TOKEN_URL='provider token url' -REACT_APP_REDIRECT_URL='provider redirect url' +POSTGRES_USER=fossy +POSTGRES_PASSWORD=change-me +POSTGRES_DB=fossology +POPULATE_DB=true +GIN_MODE=debug diff --git a/.gitignore b/.gitignore index ee44087..87e3287 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ node_modules/ .env -package-lock.json +.env.local .npm/ dist/ build/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5a89519 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2026 Siemens AG +# SPDX-License-Identifier: GPL-2.0-only +FROM node:22-alpine AS build + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . ./ + +ARG VITE_BASE_URL=/api/v1 +ARG VITE_DOMAIN_SUBDIRECTORY= +ENV VITE_BASE_URL=$VITE_BASE_URL +ENV VITE_DOMAIN_SUBDIRECTORY=$VITE_DOMAIN_SUBDIRECTORY + +RUN npm run build + +FROM nginx:1.27-alpine + +COPY nginx/default.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/build /usr/share/nginx/html + +EXPOSE 80 \ No newline at end of file diff --git a/README.md b/README.md index 779ff3c..5d9043e 100644 --- a/README.md +++ b/README.md @@ -25,25 +25,76 @@ LicenseDB backend at [http://localhost:8080/swagger/index.html](http://localhost - ```npm``` - Using a Node version manager like [```nvm```](https://github.com/nvm-sh/nvm) is strongly recommended for installing ```NodeJS``` and ```npm```. -## Set Up - -- Set the following environment variables: - - ```REACT_APP_DOMAIN_SUBDIRECTORY```: The basename of the app for situations where you can't deploy to the root of the domain, but a sub directory. - - ```PUBLIC_URL```: The URL at which the application is hosted, along with the subdirectory. - - ```REACT_APP_BASE_URL```: The URL at which backend of the application is hosted. - - ```REACT_APP_PROVIDER```: ```oidc``` or ```password```. Used to configure login mechanism of the application as OIDC or username-password. - - ```REACT_APP_CLIENT_ID```: The client id of the app instance registered with the OIDC tenant. - - ```REACT_APP_AUTH_URL```: The authorization url of the app instance registered with the OIDC tenant. - - ```REACT_APP_TOKEN_URL```: The token url of the app instance registered with the OIDC tenant. - - ```REACT_APP_REDIRECT_URL```=```http://localhost:3000/redirect``` - - See .env.example for more details. -- Install dependencies - ``` bash - npm install - ``` -- Run application - ```bash - npm start - ``` -- If everything went well, the localhost port 3000 will be opened in your host and you will be able to access the application. +## Full-Stack Docker Compose Development + +The frontend Compose file starts the UI, LicenseDB API, and PostgreSQL as one +stack. It expects a sibling checkout named `LicenseDb`: + +```text +workspace/ + LicenseDb/ + LicenseDb-UI/ +``` + +From `LicenseDb-UI`, create a local configuration file and start the stack: + +```bash +cp .env.example .env +docker compose up --build --wait +``` + +Open `http://localhost:8081`. The browser reaches the API through the UI at +`/api/v1`; PostgreSQL and the API are not published to the host. + +To use a differently named sibling checkout, such as a feature branch clone, +set `LICENSEDB_BACKEND_CONTEXT` in `.env` to its relative or absolute path. + +Validate and stop the stack with: + +```bash +docker compose config -q +docker compose ps +curl -fsS http://localhost:8081/api/v1/health +docker compose down +``` + +Do not run this stack alongside the backend repository's standalone Compose +stack. Each stack creates its own API and PostgreSQL services. Use the frontend +Compose file for full-stack development and deployment; keep the backend +Compose file for API-only development. + +### Systemd Deployment + +For a server deployment, check out `LicenseDb` and `LicenseDb-UI` as siblings +under `/opt/licensedb`, then place the real Compose variables in +`/etc/licensedb/.env`. Do not commit this file. + +Build the images once after source updates: + +```bash +cd /opt/licensedb/LicenseDb-UI +sudo /usr/bin/docker compose --env-file /etc/licensedb/.env build +``` + +Install [docs/licensedb-compose.service](docs/licensedb-compose.service) as +`/etc/systemd/system/licensedb-compose.service`, adjusting the working +directory if needed. Then enable it: + +```bash +sudo systemctl daemon-reload +sudo systemctl enable --now licensedb-compose.service +``` + +The unit starts the UI, API, and PostgreSQL after Docker and the network are +available. It waits for their health checks but does not rebuild images during +every server boot. + +## Local Frontend Development + +Set `VITE_BASE_URL` and `VITE_DOMAIN_SUBDIRECTORY` in `.env.local` as needed. +Then install dependencies and start Vite: + +```bash +npm ci +npm run dev +``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f2bc985 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,71 @@ +# SPDX-FileCopyrightText: 2026 Siemens AG +# SPDX-License-Identifier: GPL-2.0-only +services: + postgres: + image: postgres:16 + environment: + POSTGRES_USER: ${POSTGRES_USER:?set POSTGRES_USER in .env} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} + POSTGRES_DB: ${POSTGRES_DB:?set POSTGRES_DB in .env} + volumes: + - pgdata:/var/lib/postgresql/data + restart: always + healthcheck: + test: ["CMD-SHELL", "pg_isready --dbname $$POSTGRES_DB --username $$POSTGRES_USER"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - licensedb-network + + licensedb: + build: + context: ${LICENSEDB_BACKEND_CONTEXT:-../LicenseDb} + environment: + DB_HOST: postgres + DB_PORT: 5432 + DB_USER: ${POSTGRES_USER:?set POSTGRES_USER in .env} + DB_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env} + DB_NAME: ${POSTGRES_DB:?set POSTGRES_DB in .env} + POPULATE_DB: ${POPULATE_DB:-true} + GIN_MODE: ${GIN_MODE:-debug} + depends_on: + postgres: + condition: service_healthy + restart: always + healthcheck: + test: ["CMD-SHELL", "wget -q --spider http://localhost:8080/api/v1/health"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 45s + networks: + - licensedb-network + + web: + build: + context: . + args: + VITE_BASE_URL: ${VITE_BASE_URL:-/api/v1} + VITE_DOMAIN_SUBDIRECTORY: ${VITE_DOMAIN_SUBDIRECTORY:-} + ports: + - "${LICENSEDB_UI_PORT:-8081}:80" + depends_on: + licensedb: + condition: service_healthy + restart: always + healthcheck: + test: ["CMD-SHELL", "wget -q --spider http://localhost/"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 15s + networks: + - licensedb-network + +networks: + licensedb-network: + driver: bridge + +volumes: + pgdata: \ No newline at end of file diff --git a/docs/licensedb-compose.service b/docs/licensedb-compose.service new file mode 100644 index 0000000..9e7b97e --- /dev/null +++ b/docs/licensedb-compose.service @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2026 Siemens AG +# SPDX-License-Identifier: GPL-2.0-only + +[Unit] +Description=LicenseDB full-stack Docker Compose deployment +Requires=docker.service +After=docker.service network-online.target +Wants=network-online.target + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory=/opt/licensedb/LicenseDb-UI +EnvironmentFile=/etc/licensedb/.env +ExecStartPre=/usr/bin/docker compose --env-file /etc/licensedb/.env config -q +ExecStart=/usr/bin/docker compose --env-file /etc/licensedb/.env up -d --wait --wait-timeout 180 +ExecStop=/usr/bin/docker compose --env-file /etc/licensedb/.env down +TimeoutStartSec=200 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/nginx/default.conf b/nginx/default.conf new file mode 100644 index 0000000..14f5de3 --- /dev/null +++ b/nginx/default.conf @@ -0,0 +1,23 @@ +server { + listen 80; + listen [::]:80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + location /api/v1/ { + resolver 127.0.0.11 ipv6=off; + set $backend http://licensedb:8080; + proxy_pass $backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + 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; + } + + location / { + try_files $uri $uri/ /index.html; + } +} \ No newline at end of file