PWA fixed

added systemd service howto

traefik

nginix set_real_ip_from

improved readme

visuals fixed on mobile

labels removed

updated readme

fixed visuals

overlay for the hotkey

disable screen lock

clean up

git precommit hooks

clean up

clean up

update

check for update feature

added build-time information

fixed date

clean up

added hook script

fix

fix

fix

hooks fixed

webhook setup

players stay in run all timers mode

mqtt

mqtt allways connected

mqtt messages work

capturing mqtt in edit player

mqtt in Setup

updated readme

state of the mqtt

Global Pass turn

offline mode

docs: update documentation to reflect current codebase and MQTT features

- Update README.md with global MQTT commands
- Enhance architecture.md with comprehensive data model and MQTT state
- Update development.md with project structure and workflow
- Remove redundant script listings
- Fix formatting and organization
This commit is contained in:
cpu
2025-05-08 15:36:17 +02:00
parent d741efa62d
commit 4cae455892
51 changed files with 7140 additions and 2 deletions

124
docs/architecture.md Normal file
View File

@@ -0,0 +1,124 @@
## Data Model
The application maintains a comprehensive data model for managing game state:
```typescript
interface Player {
id: string; // Unique identifier for the player
name: string; // Player's name
avatar: string | null; // Player's avatar (can be null for default)
initialTimerSec: number; // Initial timer value in seconds
currentTimerSec: number; // Current timer value in seconds
hotkey: string | null; // Keyboard hotkey for player control
mqttChar: string | null; // MQTT character for player control
isSkipped: boolean; // Whether the player is skipped
isTimerRunning: boolean; // Whether the player's timer is running
isCurrent: boolean; // Whether this is the current player
isNext: boolean; // Whether this is the next player
}
interface GameState {
players: Player[]; // Array of all players
currentPlayerIndex: number; // Index of the current player
gameMode: 'normal' | 'all-timers'; // Current game mode
gameRunning: boolean; // Whether the game is currently running
isMuted: boolean; // Whether audio is muted
theme: 'light' | 'dark'; // Current theme
mqttBrokerUrl: string; // MQTT broker connection URL
mqttConnectDesired: boolean; // Whether MQTT connection is desired
mqttConnected: boolean; // Current MQTT connection status
mqttReconnectAttempts: number; // Number of reconnection attempts
mqttError: string | null; // Current MQTT error state
// Global Hotkey Controls
globalHotkeyStopPause: string | null; // Hotkey for global stop/pause
globalHotkeyRunAll: string | null; // Hotkey for run all timers
globalHotkeyPassTurn: string | null; // Hotkey for global pass turn
// Global MQTT Controls
globalMqttStopPause: string | null; // MQTT character for global stop/pause
globalMqttRunAll: string | null; // MQTT character for run all timers
globalMqttPassTurn: string | null; // MQTT character for global pass turn
}
```
## Build-time Information & Service Worker Versioning
The application incorporates build-time information and a mechanism for service worker updates:
1. **Version Management**
- Build timestamp
- Git commit hash
- Environment variables
2. **Service Worker**
- Automatic updates
- Cache management
- Offline-first approach
- Update notifications
3. **Build Process**
- Environment-specific configurations
- Asset optimization
- Code splitting
- Tree-shaking
This architecture ensures a maintainable, scalable, and performant application that meets the requirements of a multi-player timer system with remote control capabilities.
* **Minimalist Design:** Focus on clarity and ease of use. Avoid clutter.
* **Large, Clear Timers:** Timers should be easily readable at a glance.
* **Color Coding:** Use color to indicate timer state (e.g., green for running, red for negative time, grey for skipped).
* **Responsive Layout:** The UI should adapt to different (mobile phone) screen sizes.
* **Touch-Friendly:** Buttons and interactive elements should be large enough for easy tapping.
## Tech Stack
* **HTML5:** For structuring the user interface.
* **CSS3:** For styling and visual presentation, including animations. Consider a CSS framework like Tailwind CSS for rapid prototyping.
* **JavaScript:** For application logic, timer functionality, and event handling.
* **MQTT.js** for MQTT communication
* **Web Audio API:** For audio feedback (ticking sounds, alerts).
* **Browser API:** For capturing Players' photo.
* **Screen Wake Lock API:** For preventing of the screen lock in a PWA.
* **Local Storage/IndexedDB:** For persistent storage of player data, timer states, and settings.
* **Service Worker:** Essential for PWA functionality (offline access, push notifications - potential future feature).
* **Manifest File:** Defines the PWA's metadata (name, icons, theme color).
* **Web Framework:** Vith Vite (Vue.js)
* **Tailwind CSS:** Utility-first CSS framework for rapid UI development.
## Data Model (Conceptual for Setup)
```json
{
"players": [
{
"id": "1", "name": "Alice", "avatar": "image_data_or_default",
"initialTimerSec": 3600, "currentTimerSec": 3600,
"hotkey": "a", "mqttChar": "x", "isSkipped": false
}
],
"globalHotkeyStopPause": "s",
"globalMqttStopPause": "p",
"globalHotkeyRunAll": "r",
"globalMqttRunAll": "t",
"globalHotkeyPassTurn": "n",
"globalMqttPassTurn": "m",
"mqttBrokerUrl": "ws://localhost:9001",
"mqttConnectDesired": true,
"currentPlayerIndex": 0,
"gameMode": "normal",
"isMuted": false,
"theme": "light"
}
```
## Build-time Information & Service Worker Versioning
The application incorporates build-time information and a mechanism for service worker updates:
1. **Build Timestamp:**
* The build date and time are automatically injected into the application during the Vite build process.
* This is configured in `vite.config.js` using Vite's `define` feature, making `import.meta.env.VITE_APP_BUILD_TIME` available in the Vue components.
* The timestamp (formatted for the `sk-SK` locale) is displayed on the "About" screen (`src/views/InfoView.vue`).
2. **Service Worker Cache Versioning:**
* The `CACHE_VERSION` constant within the service worker (`src/sw.js`) is also dynamically generated during the Vite build.
* `vite.config.js` uses the `define` feature to replace a placeholder (`__APP_CACHE_VERSION__`) in `src/sw.js` with a unique version string. This string typically incorporates the application's version from `package.json` and a build timestamp (`Date.now()`) to ensure uniqueness.
* The `src/sw.js` file is configured as a separate Rollup entry point in `vite.config.js` so that Vite processes it and performs this replacement, outputting the final `service-worker.js` to the `dist` directory root.
* When a new version of the app is deployed with a changed `service-worker.js` (due to this new `CACHE_VERSION`), the browser detects the difference. The updated service worker installs, and upon activation, it clears out old caches associated with previous versions. This mechanism is key to how the PWA updates and provides users with the latest assets. The "Check for Update" feature on the "About" screen manually triggers the browser to check for a new `service-worker.js` file.

169
docs/deployment.md Normal file
View File

@@ -0,0 +1,169 @@
# Deployment Guide: Nexus Timer
This guide outlines the steps to deploy and manage the Nexus Timer application on a server using Docker, Traefik (as a reverse proxy), and systemd, with an optional automated deployment via Gitea webhooks.
## Table of Contents
1. [Initial Server Setup](#initial-server-setup)
2. [Exposing the App Behind Traefik](#exposing-the-app-behind-traefik-reverse-proxy)
3. [Automating Updates with Webhooks (Gitea)](#automating-updates-with-webhooks-gitea)
4. [Manual Updates (Fallback)](#manual-updates-fallback)
5. [Troubleshooting & Logs](#troubleshooting--logs)
## Initial Server Setup
### On the Server
Navigate to your preferred service directory on the server (e.g., `/virt`).
```bash
cd /virt
```
Clone the repository (only the latest commit for faster cloning).
```bash
git clone --depth 1 https://gitea.virtonline.eu/2HoursProject/nexus-timer.git
cd nexus-timer
```
If you will run the container on the Docker network `traefik` (or any other pre-existing network), find its IP subnet to allow Nginx inside the container to correctly identify the real client IP.
```bash
docker network inspect traefik --format '{{(index .IPAM.Config 0).Subnet}}'
```
You'll get an output like `172.22.0.0/16`.
Set this subnet in the `nginx.conf` file within your cloned repository before building the image. For example:
```bash
set_real_ip_from 172.22.0.0/16;
```
Build the Docker image for the application.
```bash
docker build -t virt-nexus-timer .
```
## Exposing the App Behind Traefik (Reverse Proxy)
This setup assumes you have Traefik running and configured to watch for Docker labels.
### Review the provided docker labels and systemd service file
The `docker/traefik.labels` file contains Docker labels that Traefik uses for routing and HTTPS. Review and adjust them if necessary.
Copy the example label file to its destination (one level up, to be read by systemd).
```bash
cp docker/traefik.labels labels
```
View the example systemd service definition to understand how the Docker container will be managed.
```bash
cat systemd/virt-nexus-timer.service
```
### Create the systemd service
Use `systemctl edit` to create or overwrite the service file. This is the recommended way to manage custom systemd units.
```bash
sudo systemctl edit --force --full virt-nexus-timer.service
```
The editor will open. Paste the content from your `systemd/virt-nexus-timer.service` file into the editor, then save and exit (e.g., Ctrl+X, then Y, then Enter in nano).
Enable the service to start on system boot and start it immediately.
```bash
sudo systemctl enable --now virt-nexus-timer.service
```
Check the service status to ensure it's running correctly.
```bash
systemctl status virt-nexus-timer.service
```
Look for "active (running)".
### Test the web application
Verify that the application is accessible via HTTPS through Traefik:
```bash
curl https://nexus-timer.virtonline.eu
```
Or open it in your browser:
[https://nexus-timer.virtonline.eu](https://nexus-timer.virtonline.eu)
## Automating Updates with Webhooks (Gitea)
Instead of manually pulling, building, and restarting on the server, you can automate this process using a webhook. Gitea will notify a webhook service running on your server, which will then execute a deployment script.
Install the `webhook` service
```bash
sudo install webhook
```
Allow your Gitea instance to reach the webhook service on your server (e.g., `10.0.0.1:9000`). Ensure Gitea's `ALLOWED_HOST_LIST` in its `app.ini` includes this IP.
### The Redeployment Script
The `webhook` service will execute the script `hooks/redeploy.sh`. If webhook runs as a non-root user (recommended), that user will need passwordless sudo permission to restart the `virt-nexus-timer.service`.
You can grant this by editing the sudoers file:
```bash
sudo visudo
```
and adding a line like:
```bash
webhooksvc ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart virt-nexus-timer.service
```
Replace `webhooksvc` with the actual user webhook runs as. If webhook runs as root, this is not necessary but less secure overall.
### Configure the `webhook` Service
Create or edit the main webhook configuration file, typically at `/etc/webhook.conf`. Add the JSON object from `hooks/webhook.conf` to the array in the file (or create the file if it's new).
**Note:** Replace `YOUR_VERY_STRONG_SECRET_TOKEN_HERE_REPLACE_ME` with a strong, unique secret.
### Set Up webhook as a Systemd Service
Use `systemctl edit` to create or overwrite the service file. This is the recommended way to manage custom systemd units.
```bash
sudo systemctl edit --force --full webhook.service
```
The editor will open. Paste the content from your `systemd/webhook.service` file into the editor, then save and exit (e.g., Ctrl+X, then Y, then Enter in nano).
Enable, and start the webhook service:
```bash
sudo systemctl enable --now webhook.service
sudo systemctl status webhook.service
```
### Configure Webhook in Gitea
1. Navigate to your Gitea repository: `https://gitea.virtonline.eu/2HoursProject/nexus-timer`
2. Go to `Settings -> Webhooks`.
3. Click Add Webhook and choose `Gitea`.
4. **Target URL**: `http://10.0.0.1:9000/hooks/redeploy-nexus-timer`
*(The redeploy-nexus-timer part must match the id in your /etc/webhook.conf)*
5. **HTTP Method**: POST
6. **POST Content Type**: application/json
7. **Secret**: Enter the exact same strong secret token you used in `/etc/webhook.conf` (e.g., `YOUR_VERY_STRONG_SECRET_TOKEN_HERE_REPLACE_ME`).
8. **Trigger On**:
Select `Push Events`.
You can further refine this to specific branches if your `webhook.conf` doesn't already filter by branch (though redundant filtering is fine).
9. Ensure `Enable this webhook` is checked.
10. Click `Add Webhook`.
### Test the Webhook
* In Gitea, on the Webhooks settings page for the webhook you just created, click `Test Delivery`.
* Check the Gitea UI for the response. It should show a `200 OK` and include the output from your `redeploy.sh` script.
* Push a small change to your `main` (or configured) branch to trigger a real deployment.
### Firewall Considerations
If your server has a firewall (e.g., `ufw`), ensure that port `9000` (or whichever port you configured for `webhook`) is allowed for incoming connections from your Gitea server's IP address or network.
Example for `ufw` allowing any connection to `10.0.0.1:9000` (restrict source IP if possible):
```bash
sudo ufw allow to 10.0.0.1 port 9000 proto tcp comment 'Gitea Webhook'
```
If Gitea is external, use its specific source IP instead of 'any' for better security.
```bash
sudo ufw allow from <GITEA_SERVER_IP> to 10.0.0.1 port 9000 proto tcp comment 'Gitea Webhook'
```
Reload `ufw` if changes are made:
```bash
sudo ufw reload
```
## Manual Updates (Fallback)
Navigate to the application directory on your server.
```bash
cd /virt/nexus-timer
```
Pull the latest changes from the repository, rebuild the Docker image, and restart the systemd service.
```bash
git pull && docker build -t virt-nexus-timer . && sudo systemctl restart virt-nexus-timer.service
```
The previously installed Progressive Web App (PWA) should update automatically upon next launch or offer an upgrade prompt.
## Troubleshooting & Logs
View real-time logs for the application service:
```bash
journalctl -fu virt-nexus-timer.service
```
View real-time logs for the `webhook` service:
```bash
journalctl -fu webhook.service
```
Check the custom log file for the redeployment script (if configured):
```bash
tail -f /var/log/webhook-redeploy-nexus-timer.log
```
Check Gitea's webhook delivery logs for request/response details and errors.

71
docs/development.md Normal file
View File

@@ -0,0 +1,71 @@
# Table of Contents
1. [Developer Setup Guide](#developer-setup-guide)
2. [Modify the app](#modify-the-app)
3. [Test the PWA locally](#test-the-pwa-locally)
4. [Commit & Push](#commit--push)
## Developer Setup Guide
### Project Structure
The project follows a Vue.js 3 architecture with the following key directories:
```
src/
├── assets/ # Static assets
├── components/ # Reusable Vue components
├── services/ # Business logic and API services
├── store/ # Vuex 4 state management
├── utils/ # Utility functions
├── views/ # Page-level components
├── router/ # Vue Router configuration
└── App.vue # Main application component
```
## Prerequisites
- Node.js (LTS version recommended)
- npm (comes with Node.js)
## Installation
```bash
npm install
```
## Development Server
```bash
npm run dev
```
This will start the development server with hot module replacement. The application is built using Vite, which provides:
- Fast cold start
- Instant HMR
- Optimized build process
- Modern ES module support
## Development Workflow
1. **State Management**: Use Vuex 4 for state management. All state should be handled through the store in `src/store/`.
2. **Components**: Create reusable components in `src/components/`. Use Vue 3 Composition API for component logic.
3. **Routing**: Define routes in `src/router/index.js` using Vue Router 4.
4. **Styling**: Use Tailwind CSS for styling. Additional styles can be added in `src/assets/styles/`.
5. **Services**: Place business logic and external API calls in `src/services/`.
6. **Utils**: Common utility functions should be placed in `src/utils/`.
### Modify the app
Make code changes...
### Test the PWA locally
Open it in your browser:
[http://localhost:8080/](http://localhost:8080/)
### Commit & Push
Stage changes, commit and push
```bash
git add .
git commit -m 'My cool feature'
git push
```

78
docs/remote-control.md Normal file
View File

@@ -0,0 +1,78 @@
# Remote Control Options
## Table of Contents
1. [HID Smart Buttons](#hid-smart-buttons)
2. [MQTT Remote Control](#mqtt-remote-control)
- [Mosquitto Installation Guide](#mosquitto-installation-guide)
- [Android Shortcut Setup](#android-shortcut-setup)
- [Nexus Timer Setup](#nexus-timer-setup)
## HID Smart Buttons
For an enhanced tactile experience, Nexus Timer supports Smart Buttons based on Bluetooth-connected microcontroller (e.g., XIAO nRF52840) implementing HID (Human Interface Device) protocol.
* **Buttons:** Connect 3 physical buttons, potentially extended (e.g., via 1.5m wires) for easy player access.
* **Configuration:**
* **Player 1's Button:** Single Click: Emulates a key press (e.g., 'a'). Configure this as Player 1's "Pass Turn / My Pause" hotkey in the app.
* **Player 2's Button:** Single Click: Emulates a key press (e.g., 'b'). Configure as Player 2's "Pass Turn / My Pause" hotkey.
* **Player 3's Button:** Single Click: Emulates a key press (e.g., 'c'). Configure as Player 3's "Pass Turn / My Pause" hotkey.
* **If Player 3 is Game Admin:**
* **Player 3's Button:** Long Press: Emulates a key press (e.g., 's'). Configure as the "Global Stop/Pause All" hotkey in the app.
* **Player 3's Button:** Double Click: Emulates a key press (e.g., 'x'). Configure as the "Global Run All Timers" hotkey in the app.
## MQTT Remote Control
Players can use their smartphones to send commands to Nexus Timer via MQTT. This requires an MQTT broker (like Mosquitto) on the same network.
### Mosquitto Installation Guide
**On Android (using Termux):**
1. **Install Termux** from the Play Store and run.
2. **Update packages and install Mosquitto in Termux:**
```bash
pkg update && pkg upgrade
pkg install mosquitto
```
3. **Configure the MQTT Broker:**
```bash
nano ~/.termux/etc/mosquitto/mosquitto.conf
```
Add the following configuration, then save and exit:
```
listener 1883 0.0.0.0
protocol mqtt
listener 8080 0.0.0.0
protocol websockets
allow_anonymous true
```
4. **Run Mosquitto with the configuration:**
```bash
mosquitto -c ~/.termux/etc/mosquitto/mosquitto.conf
```
* **MQTT Broker:** Needs to be accessible on the local network and configured with a WebSocket listener (e.g., `ws://<broker_ip>:<ws_port>`). Nexus Timer defaults to `ws://localhost:9001`.
### Android Shortcut Setup
* Install the "HTTP Shortcuts" app from the Play Store.
* Create a new shortcut.
* **Shortcut Type:** Choose "Execute Script" or a type that allows MQTT publishing (some versions might have direct MQTT support, or you can use Termux with `mosquitto_pub` called by the script).
* **If HTTP Shortcuts has direct MQTT publish action:**
* Configure Broker URL (e.g., `tcp://<BROKER_IP>:<TCP_PORT>`).
* Set Topic to: `game`
* Set Payload to: The single character (e.g., `a`).
* Set QoS, Retain as needed (usually 0 and false are fine).
* **If using scripting with `mosquitto_pub` (via Termux):**
* Install Termux and `mosquitto-clients` package (`pkg install mosquitto`).
* In HTTP Shortcuts, create a shortcut that executes a script.
* The script would be something like: `mosquitto_pub -h <BROKER_IP> -p <TCP_PORT> -t game -m "X"`
* Replace `<BROKER_IP>` with your Mosquitto broker's IP.
* Replace `<TCP_PORT>` with Mosquitto's TCP port (e.g., 1883). Note: `mosquitto_pub` uses TCP, while the PWA uses WebSockets to connect to the *same* broker.
* `-t game`: The topic Nexus Timer listens on.
* `-m "X"`: The single character message (e.g., "a", "b", "s"). This "X" should match the MQTT char configured in Nexus Timer for the desired action.
* **Customize Shortcut:** Give the shortcut a name (e.g., "Pass My Turn") and an icon on the Android home screen.
### Nexus Timer Setup
* Enter the MQTT Broker URL in the Setup screen and connect.
* Assign unique single characters as **MQTT Triggers** for each player's "Pass Turn / My Pause" action.
* Assign unique single characters as **MQTT Triggers** for "Global Stop/Pause All" and "Global Run All Timers".