diff --git a/.gitignore b/.gitignore
index 6864ca05e9b175b0c01783f3b83fe750d99af43f..332692a61c7b38212d491655e0528c067a33a746 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
 .env
 node_modules/
 nohup.out
+.vscode
+package-lock.json
+*.bak
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..fb4281aaf2f03be05eb1afde26a3156ccc93396f
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+FROM node:22-slim
+EXPOSE 5200
+COPY src src
+WORKDIR src
+RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends inotify-tools mosquitto-clients -y
+RUN npm install
+CMD ["chmod", "+x", "./dispense_door_opener_lookup.sh"]
+CMD ["chmod", "+x", "./start.sh"]
+CMD ["bash", "./start.sh"]
+
diff --git a/README.md b/README.md
index 89e7b805b15f9e92d21175f262de055260cb6495..375539bf90bf069270ef7fd1f6d8e135dd028d8b 100644
--- a/README.md
+++ b/README.md
@@ -6,3 +6,12 @@ A project to surface the status of the UCC door via HTTP
 1. Install requirements using `npm install`.
 2. Copy `.env.example` to `.env` and fill out required variables.
 3. Run using `npm start`.
+
+## Alt: Docker
+@pre: docker compose v2
+1. Edit compose.yaml to suit your need, mainly port and cokelog path & corresponding envvar
+2. `docker compose up -d --build`
+
+@notes:
+1. Cokelog has to mount as rw so `inotifywait` can pick it up and broadcast opener msg to mqtt broker. This *might be* unsafe. Considering original copy is on `merlo` it should be acceptable.
+
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d39c8f5a90d0c7269a011d7d60736d4b76ba7913
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,17 @@
+services:
+  node:
+    build: .
+    ports:
+      - "5200:5200"
+    volumes:
+      - type: bind
+        source: /home/other/coke/cokelog
+        target: /var/cokelog
+    environment:
+        COKELOGFILE: /var/cokelog
+    develop:
+        watch:
+          - action: sync
+            path: /home/other/coke/cokelog
+            target: /var/cokelog
+    restart: unless-stopped
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 11431f7778c9e26406557023eb51ae4929b4feef..0000000000000000000000000000000000000000
--- a/package-lock.json
+++ /dev/null
@@ -1,590 +0,0 @@
-{
-  "name": "doorsense",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "dependencies": {
-        "console-stamp": "^3.1.2",
-        "mqtt": "^5.10.1"
-      }
-    },
-    "node_modules/@babel/runtime": {
-      "version": "7.25.6",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz",
-      "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==",
-      "license": "MIT",
-      "dependencies": {
-        "regenerator-runtime": "^0.14.0"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@types/node": {
-      "version": "22.5.5",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
-      "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
-      "license": "MIT",
-      "dependencies": {
-        "undici-types": "~6.19.2"
-      }
-    },
-    "node_modules/@types/readable-stream": {
-      "version": "4.0.15",
-      "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.15.tgz",
-      "integrity": "sha512-oAZ3kw+kJFkEqyh7xORZOku1YAKvsFTogRY8kVl4vHpEKiDkfnSA/My8haRE7fvmix5Zyy+1pwzOi7yycGLBJw==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/node": "*",
-        "safe-buffer": "~5.1.1"
-      }
-    },
-    "node_modules/@types/ws": {
-      "version": "8.5.12",
-      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
-      "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/node": "*"
-      }
-    },
-    "node_modules/abort-controller": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
-      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
-      "license": "MIT",
-      "dependencies": {
-        "event-target-shim": "^5.0.0"
-      },
-      "engines": {
-        "node": ">=6.5"
-      }
-    },
-    "node_modules/ansi-styles": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-      "license": "MIT",
-      "dependencies": {
-        "color-convert": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=8"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-      }
-    },
-    "node_modules/base64-js": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "MIT"
-    },
-    "node_modules/bl": {
-      "version": "6.0.15",
-      "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.15.tgz",
-      "integrity": "sha512-RGhjD1XCPS7ZdAH6cEJVaR3gLV4KJP2hvkQ49AH5kwScjiyd0jBM8RsP4oHKzcx+kNCON9752zPeRnuv0HHwzw==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/readable-stream": "^4.0.0",
-        "buffer": "^6.0.3",
-        "inherits": "^2.0.4",
-        "readable-stream": "^4.2.0"
-      }
-    },
-    "node_modules/buffer": {
-      "version": "6.0.3",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
-      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "base64-js": "^1.3.1",
-        "ieee754": "^1.2.1"
-      }
-    },
-    "node_modules/buffer-from": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
-      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
-      "license": "MIT"
-    },
-    "node_modules/chalk": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-      "license": "MIT",
-      "dependencies": {
-        "ansi-styles": "^4.1.0",
-        "supports-color": "^7.1.0"
-      },
-      "engines": {
-        "node": ">=10"
-      },
-      "funding": {
-        "url": "https://github.com/chalk/chalk?sponsor=1"
-      }
-    },
-    "node_modules/color-convert": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-      "license": "MIT",
-      "dependencies": {
-        "color-name": "~1.1.4"
-      },
-      "engines": {
-        "node": ">=7.0.0"
-      }
-    },
-    "node_modules/color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "license": "MIT"
-    },
-    "node_modules/commist": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/commist/-/commist-3.2.0.tgz",
-      "integrity": "sha512-4PIMoPniho+LqXmpS5d3NuGYncG6XWlkBSVGiWycL22dd42OYdUGil2CWuzklaJoNxyxUSpO4MKIBU94viWNAw==",
-      "license": "MIT"
-    },
-    "node_modules/concat-stream": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
-      "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
-      "engines": [
-        "node >= 6.0"
-      ],
-      "license": "MIT",
-      "dependencies": {
-        "buffer-from": "^1.0.0",
-        "inherits": "^2.0.3",
-        "readable-stream": "^3.0.2",
-        "typedarray": "^0.0.6"
-      }
-    },
-    "node_modules/concat-stream/node_modules/readable-stream": {
-      "version": "3.6.2",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-      "license": "MIT",
-      "dependencies": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
-      },
-      "engines": {
-        "node": ">= 6"
-      }
-    },
-    "node_modules/console-stamp": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/console-stamp/-/console-stamp-3.1.2.tgz",
-      "integrity": "sha512-ab66x3NxOTxPuq71dI6gXEiw2X6ql4Le5gZz0bm7FW3FSCB00eztra/oQUuCoCGlsyKOxtULnHwphzMrRtzMBg==",
-      "license": "MIT",
-      "dependencies": {
-        "chalk": "^4.1.2",
-        "dateformat": "^4.6.3"
-      },
-      "engines": {
-        "node": ">=12"
-      }
-    },
-    "node_modules/dateformat": {
-      "version": "4.6.3",
-      "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz",
-      "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
-      "license": "MIT",
-      "engines": {
-        "node": "*"
-      }
-    },
-    "node_modules/debug": {
-      "version": "4.3.7",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
-      "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
-      "license": "MIT",
-      "dependencies": {
-        "ms": "^2.1.3"
-      },
-      "engines": {
-        "node": ">=6.0"
-      },
-      "peerDependenciesMeta": {
-        "supports-color": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/event-target-shim": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
-      "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6"
-      }
-    },
-    "node_modules/events": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
-      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=0.8.x"
-      }
-    },
-    "node_modules/fast-unique-numbers": {
-      "version": "8.0.13",
-      "resolved": "https://registry.npmjs.org/fast-unique-numbers/-/fast-unique-numbers-8.0.13.tgz",
-      "integrity": "sha512-7OnTFAVPefgw2eBJ1xj2PGGR9FwYzSUso9decayHgCDX4sJkHLdcsYTytTg+tYv+wKF3U8gJuSBz2jJpQV4u/g==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.23.8",
-        "tslib": "^2.6.2"
-      },
-      "engines": {
-        "node": ">=16.1.0"
-      }
-    },
-    "node_modules/has-flag": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/help-me": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
-      "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
-      "license": "MIT"
-    },
-    "node_modules/ieee754": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "BSD-3-Clause"
-    },
-    "node_modules/inherits": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-      "license": "ISC"
-    },
-    "node_modules/js-sdsl": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
-      "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
-      "license": "MIT",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/js-sdsl"
-      }
-    },
-    "node_modules/lru-cache": {
-      "version": "10.4.3",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
-      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
-      "license": "ISC"
-    },
-    "node_modules/minimist": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
-    "node_modules/mqtt": {
-      "version": "5.10.1",
-      "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-5.10.1.tgz",
-      "integrity": "sha512-hXCOki8sANoQ7w+2OzJzg6qMBxTtrH9RlnVNV8panLZgnl+Gh0J/t4k6r8Az8+C7y3KAcyXtn0mmLixyUom8Sw==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/readable-stream": "^4.0.5",
-        "@types/ws": "^8.5.9",
-        "commist": "^3.2.0",
-        "concat-stream": "^2.0.0",
-        "debug": "^4.3.4",
-        "help-me": "^5.0.0",
-        "lru-cache": "^10.0.1",
-        "minimist": "^1.2.8",
-        "mqtt-packet": "^9.0.0",
-        "number-allocator": "^1.0.14",
-        "readable-stream": "^4.4.2",
-        "reinterval": "^1.1.0",
-        "rfdc": "^1.3.0",
-        "split2": "^4.2.0",
-        "worker-timers": "^7.1.4",
-        "ws": "^8.17.1"
-      },
-      "bin": {
-        "mqtt": "build/bin/mqtt.js",
-        "mqtt_pub": "build/bin/pub.js",
-        "mqtt_sub": "build/bin/sub.js"
-      },
-      "engines": {
-        "node": ">=16.0.0"
-      }
-    },
-    "node_modules/mqtt-packet": {
-      "version": "9.0.0",
-      "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-9.0.0.tgz",
-      "integrity": "sha512-8v+HkX+fwbodsWAZIZTI074XIoxVBOmPeggQuDFCGg1SqNcC+uoRMWu7J6QlJPqIUIJXmjNYYHxBBLr1Y/Df4w==",
-      "license": "MIT",
-      "dependencies": {
-        "bl": "^6.0.8",
-        "debug": "^4.3.4",
-        "process-nextick-args": "^2.0.1"
-      }
-    },
-    "node_modules/ms": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-      "license": "MIT"
-    },
-    "node_modules/number-allocator": {
-      "version": "1.0.14",
-      "resolved": "https://registry.npmjs.org/number-allocator/-/number-allocator-1.0.14.tgz",
-      "integrity": "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA==",
-      "license": "MIT",
-      "dependencies": {
-        "debug": "^4.3.1",
-        "js-sdsl": "4.3.0"
-      }
-    },
-    "node_modules/process": {
-      "version": "0.11.10",
-      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
-      "license": "MIT",
-      "engines": {
-        "node": ">= 0.6.0"
-      }
-    },
-    "node_modules/process-nextick-args": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
-      "license": "MIT"
-    },
-    "node_modules/readable-stream": {
-      "version": "4.5.2",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
-      "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
-      "license": "MIT",
-      "dependencies": {
-        "abort-controller": "^3.0.0",
-        "buffer": "^6.0.3",
-        "events": "^3.3.0",
-        "process": "^0.11.10",
-        "string_decoder": "^1.3.0"
-      },
-      "engines": {
-        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-      }
-    },
-    "node_modules/regenerator-runtime": {
-      "version": "0.14.1",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
-      "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
-      "license": "MIT"
-    },
-    "node_modules/reinterval": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz",
-      "integrity": "sha512-QIRet3SYrGp0HUHO88jVskiG6seqUGC5iAG7AwI/BV4ypGcuqk9Du6YQBUOUqm9c8pw1eyLoIaONifRua1lsEQ==",
-      "license": "MIT"
-    },
-    "node_modules/rfdc": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
-      "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
-      "license": "MIT"
-    },
-    "node_modules/safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-      "license": "MIT"
-    },
-    "node_modules/split2": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
-      "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
-      "license": "ISC",
-      "engines": {
-        "node": ">= 10.x"
-      }
-    },
-    "node_modules/string_decoder": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
-      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
-      "license": "MIT",
-      "dependencies": {
-        "safe-buffer": "~5.2.0"
-      }
-    },
-    "node_modules/string_decoder/node_modules/safe-buffer": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-      "funding": [
-        {
-          "type": "github",
-          "url": "https://github.com/sponsors/feross"
-        },
-        {
-          "type": "patreon",
-          "url": "https://www.patreon.com/feross"
-        },
-        {
-          "type": "consulting",
-          "url": "https://feross.org/support"
-        }
-      ],
-      "license": "MIT"
-    },
-    "node_modules/supports-color": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-      "license": "MIT",
-      "dependencies": {
-        "has-flag": "^4.0.0"
-      },
-      "engines": {
-        "node": ">=8"
-      }
-    },
-    "node_modules/tslib": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
-      "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
-      "license": "0BSD"
-    },
-    "node_modules/typedarray": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
-      "license": "MIT"
-    },
-    "node_modules/undici-types": {
-      "version": "6.19.8",
-      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
-      "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
-      "license": "MIT"
-    },
-    "node_modules/util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
-      "license": "MIT"
-    },
-    "node_modules/worker-timers": {
-      "version": "7.1.8",
-      "resolved": "https://registry.npmjs.org/worker-timers/-/worker-timers-7.1.8.tgz",
-      "integrity": "sha512-R54psRKYVLuzff7c1OTFcq/4Hue5Vlz4bFtNEIarpSiCYhpifHU3aIQI29S84o1j87ePCYqbmEJPqwBTf+3sfw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.24.5",
-        "tslib": "^2.6.2",
-        "worker-timers-broker": "^6.1.8",
-        "worker-timers-worker": "^7.0.71"
-      }
-    },
-    "node_modules/worker-timers-broker": {
-      "version": "6.1.8",
-      "resolved": "https://registry.npmjs.org/worker-timers-broker/-/worker-timers-broker-6.1.8.tgz",
-      "integrity": "sha512-FUCJu9jlK3A8WqLTKXM9E6kAmI/dR1vAJ8dHYLMisLNB/n3GuaFIjJ7pn16ZcD1zCOf7P6H62lWIEBi+yz/zQQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.24.5",
-        "fast-unique-numbers": "^8.0.13",
-        "tslib": "^2.6.2",
-        "worker-timers-worker": "^7.0.71"
-      }
-    },
-    "node_modules/worker-timers-worker": {
-      "version": "7.0.71",
-      "resolved": "https://registry.npmjs.org/worker-timers-worker/-/worker-timers-worker-7.0.71.tgz",
-      "integrity": "sha512-ks/5YKwZsto1c2vmljroppOKCivB/ma97g9y77MAAz2TBBjPPgpoOiS1qYQKIgvGTr2QYPT3XhJWIB6Rj2MVPQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/runtime": "^7.24.5",
-        "tslib": "^2.6.2"
-      }
-    },
-    "node_modules/ws": {
-      "version": "8.18.0",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
-      "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=10.0.0"
-      },
-      "peerDependencies": {
-        "bufferutil": "^4.0.1",
-        "utf-8-validate": ">=5.0.2"
-      },
-      "peerDependenciesMeta": {
-        "bufferutil": {
-          "optional": true
-        },
-        "utf-8-validate": {
-          "optional": true
-        }
-      }
-    }
-  }
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index 37d91accbd95617e3be7d8e41b6a707dada5340d..0000000000000000000000000000000000000000
--- a/package.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "dependencies": {
-    "console-stamp": "^3.1.2",
-    "mqtt": "^5.10.1"
-  },
-  "scripts": {
-    "start": "node --env-file=.env main.js"
-  }
-}
diff --git a/src/dispense_door_opener_lookup.sh b/src/dispense_door_opener_lookup.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a79665456f4f0760355a8af05405ca355c26c29c
--- /dev/null
+++ b/src/dispense_door_opener_lookup.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# [ROY] 20250525
+set -e
+set -x
+source ./.env
+
+# this path should be injected as envvar; only use it as debug
+#COKELOGFILE=/home/other/coke/cokelog
+
+[[ -n "$COKELOGFILE" ]]
+[[ -n "$MQTT_HOST" ]]
+[[ -n "$MQTT_PORT" ]]
+[[ -n "$MQTT_USER" ]]
+[[ -n "$MQTT_PASS" ]]
+[[ -r "$COKELOGFILE" ]]
+
+PATTERN_DOOR="dispense 'door' \(door:[[:digit:]]\) for (\S*) by (\S*)"
+PATTERN_TAKEDOOR="dispense 'takedoor' \(pseudo:[[:digit:]][[:digit:]]\) for (\S*) by (\S*)"
+MAX_LOOKBACK=100
+# Grab the latest user who dispensed door whenever inotify detects the mounted cokelog is changed. A better way is to monitor MQTT channel for doorstate instead
+
+inotifywait -m -e close_write "$COKELOGFILE" | while read -r filename event event_filename; do
+  opener=""
+  # Declare offset to be an integer type, or else "offset+=10" will be a string concat
+  declare -i offset
+  offset=0
+  while [[ -z "$opener" && "$offset" -le "$MAX_LOOKBACK" ]]; do
+    lines=$(tail -n "+${offset}" "${COKELOGFILE}" | tac)
+    # Don't double quote $lines, or set IFS to empty, so that $lines won't get zapped into one line
+    while IFS='' read -r line; do
+      if [[ "$line" =~ $PATTERN_DOOR || "$line" =~ $PATTERN_TAKEDOOR ]]; then
+        echo "${BASH_REMATCH[1]}"
+        opener="${BASH_REMATCH[1]}"
+        break
+      fi
+    done <<<"$lines"
+    offset+=10
+  done
+  if [[ -z "$opener" ]]; then 
+    opener="UNEXPECTED ERROR, OPENER NOT FOUND, CONTACT TECH SUPPORT"
+  fi
+  mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" --username "$MQTT_USER" --pw "$MQTT_PASS" -t "door/ucc-door/openedby" -m "$opener"
+done
+
diff --git a/main.js b/src/main.js
similarity index 98%
rename from main.js
rename to src/main.js
index a9ba658cde9bb9b3be77b16331ae77dcdb94568d..74708554df739ec19db7b8c7d12d2a5dd06c3c41 100644
--- a/main.js
+++ b/src/main.js
@@ -1,3 +1,5 @@
+// edited 2025-05-24 [ROY] for fixing error-state npm program
+require('dotenv').config()
 const mqtt = require('mqtt');
 const http = require('http');
 const fs = require('node:fs');
@@ -22,7 +24,7 @@ const mqtt_port = process.env.MQTT_PORT;
 
 // Use a randomized client ID to avoid collisions, as we don't need any kind
 // of session resumption
-const clientId = crypto.randomUUID();
+const clientId = "doorsense-"+crypto.randomUUID();
 
 // Create an MQTT client instance
 const options = {
diff --git a/src/package.json b/src/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..6b491a0c97ad01995df46070d2e5645ae22956df
--- /dev/null
+++ b/src/package.json
@@ -0,0 +1,13 @@
+{
+  "name": "@ucc/doorsense",
+  "private": true,
+  "dependencies": {
+    "console-stamp": "^3.1.2",
+    "dotenv": "^16.5.0",
+    "mqtt": "^5.10.1",
+    "package.json": "^2.0.1"
+  },
+  "scripts": {
+    "start": "node main.js"
+  }
+}
diff --git a/pages/ucc_door_closed.html b/src/pages/ucc_door_closed.html
similarity index 100%
rename from pages/ucc_door_closed.html
rename to src/pages/ucc_door_closed.html
diff --git a/pages/ucc_door_open.html b/src/pages/ucc_door_open.html
similarity index 100%
rename from pages/ucc_door_open.html
rename to src/pages/ucc_door_open.html
diff --git a/pages/ucc_door_unavail.html b/src/pages/ucc_door_unavail.html
similarity index 100%
rename from pages/ucc_door_unavail.html
rename to src/pages/ucc_door_unavail.html
diff --git a/pages/unisfa_door_closed.html b/src/pages/unisfa_door_closed.html
similarity index 100%
rename from pages/unisfa_door_closed.html
rename to src/pages/unisfa_door_closed.html
diff --git a/pages/unisfa_door_open.html b/src/pages/unisfa_door_open.html
similarity index 100%
rename from pages/unisfa_door_open.html
rename to src/pages/unisfa_door_open.html
diff --git a/pages/unisfa_door_unavail.html b/src/pages/unisfa_door_unavail.html
similarity index 100%
rename from pages/unisfa_door_unavail.html
rename to src/pages/unisfa_door_unavail.html
diff --git a/pages/uwaes_door_closed.html b/src/pages/uwaes_door_closed.html
similarity index 100%
rename from pages/uwaes_door_closed.html
rename to src/pages/uwaes_door_closed.html
diff --git a/pages/uwaes_door_open.html b/src/pages/uwaes_door_open.html
similarity index 100%
rename from pages/uwaes_door_open.html
rename to src/pages/uwaes_door_open.html
diff --git a/pages/uwaes_door_unavail.html b/src/pages/uwaes_door_unavail.html
similarity index 100%
rename from pages/uwaes_door_unavail.html
rename to src/pages/uwaes_door_unavail.html
diff --git a/src/start.sh b/src/start.sh
new file mode 100644
index 0000000000000000000000000000000000000000..c0901dc24d33ad758ca5a622b499eff7e7e51e52
--- /dev/null
+++ b/src/start.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+bash ./dispense_door_opener_lookup.sh &
+node main.js &
+
+wait -n
+exit $?
diff --git a/static/darkmode.js b/src/static/darkmode.js
similarity index 100%
rename from static/darkmode.js
rename to src/static/darkmode.js
diff --git a/static/door_ucc_closed.jpg b/src/static/door_ucc_closed.jpg
similarity index 100%
rename from static/door_ucc_closed.jpg
rename to src/static/door_ucc_closed.jpg
diff --git a/static/door_ucc_open.jpg b/src/static/door_ucc_open.jpg
similarity index 100%
rename from static/door_ucc_open.jpg
rename to src/static/door_ucc_open.jpg
diff --git a/static/door_unisfa_closed.jpg b/src/static/door_unisfa_closed.jpg
similarity index 100%
rename from static/door_unisfa_closed.jpg
rename to src/static/door_unisfa_closed.jpg
diff --git a/static/door_unisfa_open.jpg b/src/static/door_unisfa_open.jpg
similarity index 100%
rename from static/door_unisfa_open.jpg
rename to src/static/door_unisfa_open.jpg
diff --git a/static/door_uwaes_closed.jpg b/src/static/door_uwaes_closed.jpg
similarity index 100%
rename from static/door_uwaes_closed.jpg
rename to src/static/door_uwaes_closed.jpg
diff --git a/static/door_uwaes_open.jpg b/src/static/door_uwaes_open.jpg
similarity index 100%
rename from static/door_uwaes_open.jpg
rename to src/static/door_uwaes_open.jpg
diff --git a/static/style.css b/src/static/style.css
similarity index 100%
rename from static/style.css
rename to src/static/style.css