Skip to content

Commit 8cee958

Browse files
committed
Merge PR #98: Updates and improvements to dash panel
- Require Node 20+; update runtime/packages; drop older Node support - Upgrade to Multer 2.x; fix dependency resolution and empty request body errors - Add POOL_WEB* env vars to override web settings at runtime - Recover from corrupt config.json before defaults; migrate legacy absolute paths; warn if config not writable; improve first-run handling - Warn in UI when internal-only hostnames are detected - Handle missing git gracefully during version/branch checks - Add sample docker-compose.yml with practical defaults and device mapping examples - Refresh Docker build process and cache settings - Update README with compose example, env overrides, config paths, and permissions - Update version to 8.3.0
2 parents 16f008a + c06f449 commit 8cee958

14 files changed

Lines changed: 799 additions & 314 deletions

.github/copilot-instructions.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# nodejs-poolController-dashPanel AI Coding Instructions
2+
3+
## Project Overview
4+
This is a TypeScript-based web dashboard for pool control systems that acts as a frontend relay to a separate [nodejs-poolController](https://github.com/tagyoureit/nodejs-poolController) backend server. It provides a web interface for pool management and an RS485 message debugging tool.
5+
6+
## Architecture & Key Components
7+
8+
### Core Service Pattern
9+
- **Main entry**: `app.ts` orchestrates initialization of config → logger → webApp → outQueues
10+
- **Configuration**: Lives in `server/config/Config.ts` with defaults in `defaultConfig.json`
11+
- **Web server**: Multi-protocol support (HTTP/HTTPS/HTTP2) in `server/Server.ts` with Socket.IO for real-time updates
12+
- **Relay pattern**: All `/njsPC/*` requests are proxied to the backend pool controller via `server/relay/relayRoute.ts`
13+
14+
### Frontend Organization
15+
- **Widget-based UI**: jQuery widgets in `scripts/` for dashboard components (bodies, circuits, pumps, chemistry, etc.)
16+
- **Theme system**: SCSS-based themes in `themes/` with Bootstrap integration
17+
- **Real-time updates**: Socket.IO client-server communication for live pool data
18+
19+
### Message System
20+
- **Message Manager**: Dedicated tool for RS485 protocol debugging in `scripts/messages/`
21+
- **Documentation**: Message protocol docs in `server/messages/docs/`
22+
- **Filtering**: Advanced message filtering and decoding capabilities
23+
24+
## Development Workflows
25+
26+
### Build & Run
27+
```bash
28+
npm run build # TypeScript compilation to dist/
29+
npm start # Build + run compiled app
30+
npm run watch # Watch mode for development
31+
```
32+
33+
### Deployment
34+
- **Docker**: Multi-stage build, runs on port 5150, uses PM2 with `ecosystem.config.js`
35+
- **Config**: Backend server connection configured via web UI or manual `config.json` edit
36+
37+
## Code Patterns & Conventions
38+
39+
### TypeScript Structure
40+
- **Modules**: CommonJS with ESNext target
41+
- **Classes**: Singleton pattern for services (webApp, config, logger, outQueues)
42+
- **Error handling**: Custom `ApiError` class extends Error
43+
- **Constants**: Shared utilities in `server/Constants.ts`
44+
45+
### Frontend Patterns
46+
- **jQuery widgets**: Use `$.widget("pic.widgetName", {})` pattern for all UI components
47+
- **Socket events**: Widgets implement receive methods (e.g., `receiveLogMessages`, `receivePortStats`)
48+
- **Panel initialization**: Each widget has an `init` method that accepts data from the backend
49+
50+
### Configuration
51+
- **Hierarchical config**: Web servers, services, and relay settings in nested objects
52+
- **Runtime config**: Web UI allows editing pool controller connection settings
53+
- **Default ports**: Dashboard on 5150, typically connects to pool controller on 4200
54+
55+
### API Structure
56+
- **Config API**: `/config/*` routes for dashboard settings
57+
- **Messages API**: `/messages/*` for RS485 message management
58+
- **Relay pattern**: `/njsPC/*` proxies everything to backend pool controller
59+
- **Upload**: File upload functionality for logs and configs
60+
61+
## Integration Points
62+
63+
### Backend Communication
64+
- **Primary**: Socket.IO connection to nodejs-poolController for real-time pool data
65+
- **Fallback**: HTTP relay for REST API calls when socket unavailable
66+
- **Message relay**: Bidirectional RS485 message passthrough for debugging
67+
68+
### External Dependencies
69+
- **Pool protocols**: IntelliCenter, IntelliTouch, EasyTouch support via backend
70+
- **Network discovery**: SSDP and mDNS for auto-discovery of pool controllers
71+
- **Authentication**: Optional HTTP basic auth with htpasswd files
72+
73+
## Key Files to Understand
74+
- `app.ts` - Application entry and initialization sequence
75+
- `server/Server.ts` - Multi-protocol web server with Socket.IO
76+
- `server/relay/relayRoute.ts` - Backend proxy implementation
77+
- `scripts/dashboard.js` - Main dashboard widget orchestration
78+
- `defaultConfig.json` - Complete configuration schema and defaults
79+
- `ecosystem.config.js` - PM2 process management for production

.github/workflows/docker-publish-njsPC-linux.yml

Lines changed: 0 additions & 50 deletions
This file was deleted.

.github/workflows/ghcr-publish.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Publish Docker Image - dashPanel (GHCR)
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
tags:
8+
- 'v*.*.*'
9+
workflow_dispatch:
10+
11+
jobs:
12+
build-and-push:
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
packages: write
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Docker meta
22+
id: meta
23+
uses: docker/metadata-action@v5
24+
with:
25+
images: |
26+
ghcr.io/${{ github.repository_owner }}/njspc-dash
27+
tags: |
28+
type=ref,event=branch
29+
type=ref,event=pr
30+
type=semver,pattern={{version}}
31+
type=semver,pattern={{major}}.{{minor}}
32+
type=semver,pattern={{major}}
33+
type=sha
34+
type=raw,value=latest,enable={{is_default_branch}}
35+
labels: |
36+
org.opencontainers.image.source=${{ github.repository }}
37+
org.opencontainers.image.revision=${{ github.sha }}
38+
org.opencontainers.image.title=njspc-dash
39+
org.opencontainers.image.description=Web UI dashboard for nodejs-poolController (GHCR image)
40+
41+
- name: Set up QEMU
42+
uses: docker/setup-qemu-action@v3
43+
44+
- name: Set up Docker Buildx
45+
uses: docker/setup-buildx-action@v3
46+
47+
- name: Login to GHCR
48+
uses: docker/login-action@v3
49+
with:
50+
registry: ghcr.io
51+
username: ${{ github.actor }}
52+
password: ${{ secrets.GITHUB_TOKEN }}
53+
54+
- name: Build and push
55+
uses: docker/build-push-action@v6
56+
with:
57+
context: .
58+
push: true
59+
platforms: linux/amd64,linux/arm64,linux/arm/v7
60+
tags: ${{ steps.meta.outputs.tags }}
61+
labels: ${{ steps.meta.outputs.labels }}
62+
cache-from: type=gha
63+
cache-to: type=gha,mode=max
64+
65+
- name: Echo published tags
66+
run: |
67+
echo "Published: ${{ steps.meta.outputs.tags }}"

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
20

Dockerfile

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,53 @@
1-
FROM node:alpine as build
2-
RUN apk add --no-cache make gcc g++ python3 linux-headers udev tzdata
1+
### Build stage
2+
FROM node:20-alpine AS build
3+
LABEL maintainer="nodejs-poolController"
4+
5+
# Install build toolchain only for native deps (ssdp, possible future serial libs, etc.)
6+
RUN apk add --no-cache make gcc g++ python3 linux-headers udev tzdata git
7+
38
WORKDIR /app
9+
10+
# Copy manifests first to leverage Docker layer caching
411
COPY package*.json ./
12+
COPY defaultConfig.json config.json
13+
514
RUN npm ci
615
COPY . .
716
RUN npm run build
8-
RUN npm ci --omit=dev
917

10-
FROM node:alpine
11-
RUN apk add git
12-
RUN mkdir /app && chown node:node /app && mkdir /app/data && chown node:node /app/data
18+
# Prune to production dependencies only (keeps node_modules consistent with lockfile)
19+
RUN npm prune --production
20+
21+
### Runtime stage
22+
FROM node:20-alpine AS runtime
23+
ENV NODE_ENV=production
24+
1325
WORKDIR /app
14-
COPY --chown=node:node --from=build /app .
26+
27+
# Prepare runtime directories (match application expectations)
28+
RUN mkdir -p /app/logs /app/data /app/uploads /app/backups \
29+
&& chown -R node:node /app/logs /app/data /app/uploads /app/backups || true
30+
31+
# Copy only required runtime artifacts from build stage
32+
COPY --chown=node:node --from=build /app/package*.json ./
33+
COPY --chown=node:node --from=build /app/node_modules ./node_modules
34+
COPY --chown=node:node --from=build /app/dist ./dist
35+
COPY --chown=node:node --from=build /app/defaultConfig.json ./defaultConfig.json
36+
COPY --chown=node:node --from=build /app/config.json ./config.json
37+
COPY --chown=node:node --from=build /app/README.md ./README.md
38+
COPY --chown=node:node --from=build /app/themes ./themes
39+
COPY --chown=node:node --from=build /app/pages ./pages
40+
COPY --chown=node:node --from=build /app/scripts ./scripts
41+
COPY --chown=node:node --from=build /app/server/messages/docs ./server/messages/docs
42+
1543
USER node
16-
ENV NODE_ENV=production
17-
EXPOSE 4200
44+
45+
# Expose dashboard port (HTTP). HTTPS optional per config (5151)
46+
EXPOSE 5150 5151
47+
48+
# Healthcheck: perform lightweight HTTP request to ensure app responding
49+
RUN apk add --no-cache curl
50+
HEALTHCHECK --interval=30s --timeout=5s --start-period=45s --retries=5 \
51+
CMD curl -fsS http://127.0.0.1:5150/config/appVersion?health || exit 1
52+
1853
ENTRYPOINT ["node", "dist/app.js"]

README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,93 @@ To configure the dashPanel you need to place the url for your [nodejs-poolContro
1212
Message manager allows you to inspect your RS485 communication coming from and going to the [nodejs-poolController](https://github.com/tagyoureit/nodejs-poolController) server. This tool decodes the messages and displays them in a manner where important chatter on the RS485 connection can be decoded while eliminating the chatter that don't matter. Special filters can be applied to reduce the information to only the items you are interested in.
1313
![image](https://user-images.githubusercontent.com/47839015/83314254-7a92d700-a1ce-11ea-8891-545db084624e.png)
1414

15+
## Quick Start (docker-compose)
16+
Below is a minimal example running both the backend `nodejs-poolController` (service name `njspc`) and this dashPanel UI (service name `njspc-dash`). Adjust volumes and device mappings as needed. The dashPanel writes its configuration to `/app/config.json`, so we bind mount a host file to persist it. Additional runtime state (queues/uploads/logs) uses named volumes.
17+
18+
```yaml
19+
services:
20+
njspc:
21+
image: ghcr.io/sam2kb/njspc
22+
container_name: njspc
23+
restart: unless-stopped
24+
environment:
25+
- TZ=${TZ:-UTC}
26+
- NODE_ENV=production
27+
# Serial vs network connection options
28+
# - POOL_NET_CONNECT=true
29+
# - POOL_NET_HOST=raspberrypi
30+
# - POOL_NET_PORT=9801
31+
# Provide coordinates so sunrise/sunset (heliotrope) works immediately - change as needed
32+
- POOL_LATITUDE=28.5383
33+
- POOL_LONGITUDE=-81.3792
34+
ports:
35+
- "4200:4200"
36+
devices:
37+
- /dev/ttyACM0:/dev/ttyUSB0
38+
# Persistence (create host directories/files first)
39+
volumes:
40+
- ./server-config.json:/app/config.json # Persisted config file on host
41+
- njspc-data:/app/data # State & equipment snapshots
42+
- njspc-backups:/app/backups # Backup archives
43+
- njspc-logs:/app/logs # Logs
44+
- njspc-bindings:/app/web/bindings/custom # Custom bindings
45+
# OPTIONAL: If you get permission errors accessing /dev/tty*, prefer adding the container user to the host dialout/uucp group;
46+
# only as a last resort temporarily uncomment the two lines below to run privileged/root (less secure).
47+
# privileged: true
48+
# user: "0:0"
49+
50+
njspc-dash:
51+
image: ghcr.io/sam2kb/njspc-dash
52+
container_name: njspc-dash
53+
restart: unless-stopped
54+
depends_on:
55+
- njspc
56+
environment:
57+
- TZ=${TZ:-UTC}
58+
- NODE_ENV=production
59+
- POOL_WEB_SERVICES_IP=njspc # Link to backend service name
60+
ports:
61+
- "5150:5150"
62+
volumes:
63+
- ./dash-config.json:/app/config.json
64+
- njspc-dash-data:/app/data
65+
- njspc-dash-logs:/app/logs
66+
- njspc-dash-uploads:/app/uploads
67+
68+
volumes:
69+
njspc-data:
70+
njspc-backups:
71+
njspc-logs:
72+
njspc-bindings:
73+
njspc-dash-data:
74+
njspc-dash-logs:
75+
njspc-dash-uploads:
76+
```
77+
78+
After starting, browse to: `http://localhost:5150` and configure any remaining settings via the UI. The dashPanel will connect automatically to `njspc:4200` unless overridden.
79+
80+
## Persistence & Configuration
81+
The application loads configuration from `/app/config.json` at startup and rewrites it atomically after changes (writes to a temporary file then renames). To persist across container recreations:
82+
83+
1. Create a host directory and seed the file (optional – if omitted, an empty file will be populated after first change):
84+
```bash
85+
mkdir -p config
86+
docker run --rm ghcr.io/sam2kb/njspc-dash cat /app/config.json > config/config.json
87+
```
88+
2. Use the bind mount shown in the compose example: `./config/config.json:/app/config.json`.
89+
3. If the mounted file is empty, defaults + environment overrides are applied and the file will be written once you change settings via the UI/API.
90+
91+
If a write is interrupted, the app can recover from a `.tmp` file; if corruption is detected the previous file is backed up as `config.json.corrupt` (when non-empty) and defaults are re-applied.
92+
93+
Environment variable overrides (new hierarchical form) include:
94+
* `POOL_WEB_SERVICES_IP`
95+
* `POOL_WEB_SERVICES_PORT`
96+
* `POOL_WEB_SERVICES_PROTOCOL`
97+
* `POOL_WEB_SERVERS_HTTP_PORT`, `POOL_WEB_SERVERS_HTTPS_PORT`
98+
* `POOL_WEB_SERVERS_HTTP_ENABLED`, `POOL_WEB_SERVERS_HTTPS_ENABLED`
99+
100+
Legacy variables `POOL_HTTP_IP` and `POOL_HTTP_PORT` are still honored.
101+
102+
For production hardenings consider: enabling HTTPS, adding reverse proxy headers, mounting persistent volumes, and restricting exposed ports. Ensure ownership of the mounted `config.json` permits writes by the container user (UID 1000 in the official image); otherwise configuration changes will be disabled.
103+
15104

0 commit comments

Comments
 (0)