|
@@ -0,0 +1,308 @@
|
|
|
|
|
+# Deployment Guide
|
|
|
|
|
+
|
|
|
|
|
+This application can run on basic shared webhosting because it uses:
|
|
|
|
|
+
|
|
|
|
|
+- plain PHP
|
|
|
|
|
+- no database
|
|
|
|
|
+- no Composer dependencies
|
|
|
|
|
+- JSON files for persistence
|
|
|
|
|
+
|
|
|
|
|
+The deployment target assumed by this guide is a classic shared hosting account with a document root such as `public_html/`.
|
|
|
|
|
+
|
|
|
|
|
+## Requirements
|
|
|
|
|
+
|
|
|
|
|
+Required:
|
|
|
|
|
+
|
|
|
|
|
+- PHP 8.1 or newer recommended
|
|
|
|
|
+- PHP sessions enabled
|
|
|
|
|
+- permission for PHP to read `src/` and read/write `data/`
|
|
|
|
|
+- domain or subdomain pointing to the app
|
|
|
|
|
+
|
|
|
|
|
+Optional but useful:
|
|
|
|
|
+
|
|
|
|
|
+- working `mail()` configuration for email alerts
|
|
|
|
|
+- `allow_url_fopen` enabled for webhook alerts
|
|
|
|
|
+- outbound HTTPS requests for webhook alerts
|
|
|
|
|
+- browser access to `cdn.jsdelivr.net` if `/docs/` should load Swagger UI
|
|
|
|
|
+
|
|
|
|
|
+Not required:
|
|
|
|
|
+
|
|
|
|
|
+- database
|
|
|
|
|
+- Composer
|
|
|
|
|
+- Node.js
|
|
|
|
|
+- cron job
|
|
|
|
|
+
|
|
|
|
|
+## Important Deployment Limitation
|
|
|
|
|
+
|
|
|
|
|
+The current app is written for deployment at the web root of a domain or subdomain, for example:
|
|
|
|
|
+
|
|
|
|
|
+- `https://monitor.example.com/`
|
|
|
|
|
+- `https://example.com/`
|
|
|
|
|
+
|
|
|
|
|
+It is currently **not prepared for deployment in a subfolder** such as `https://example.com/monitor/`, because the frontend uses root-relative URLs like:
|
|
|
|
|
+
|
|
|
|
|
+- `/styles.css`
|
|
|
|
|
+- `/app.js`
|
|
|
|
|
+- `/admin/`
|
|
|
|
|
+- `/api/v1/status.php`
|
|
|
|
|
+
|
|
|
|
|
+If subfolder deployment is needed later, the code should be adjusted first.
|
|
|
|
|
+
|
|
|
|
|
+## Where Everything Should Be
|
|
|
|
|
+
|
|
|
|
|
+### Preferred layout if the host allows a custom document root
|
|
|
|
|
+
|
|
|
|
|
+Keep the repository structure as-is and point the domain document root to `public/`.
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+/home/account/getraenke-monitor/
|
|
|
|
|
+├── data/
|
|
|
|
|
+│ ├── alert_log.json
|
|
|
|
|
+│ ├── config.json
|
|
|
|
|
+│ └── state.json
|
|
|
|
|
+├── public/ <- document root
|
|
|
|
|
+│ ├── admin/
|
|
|
|
|
+│ ├── api/
|
|
|
|
|
+│ ├── docs/
|
|
|
|
|
+│ ├── app.js
|
|
|
|
|
+│ ├── index.php
|
|
|
|
|
+│ ├── openapi.yaml
|
|
|
|
|
+│ └── styles.css
|
|
|
|
|
+└── src/
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### Recommended layout for basic shared hosting with `public_html/`
|
|
|
|
|
+
|
|
|
|
|
+If the host does not let you choose `public/` as document root, upload the files like this:
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+/home/account/
|
|
|
|
|
+├── data/
|
|
|
|
|
+│ ├── alert_log.json
|
|
|
|
|
+│ ├── config.json
|
|
|
|
|
+│ └── state.json
|
|
|
|
|
+├── public_html/ <- public contents go here
|
|
|
|
|
+│ ├── admin/
|
|
|
|
|
+│ ├── api/
|
|
|
|
|
+│ ├── docs/
|
|
|
|
|
+│ ├── app.js
|
|
|
|
|
+│ ├── index.php
|
|
|
|
|
+│ ├── openapi.yaml
|
|
|
|
|
+│ └── styles.css
|
|
|
|
|
+└── src/
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+Important:
|
|
|
|
|
+
|
|
|
|
|
+- upload the **contents of `public/`** into `public_html/`
|
|
|
|
|
+- upload `src/` next to `public_html/`, not inside it
|
|
|
|
|
+- upload `data/` next to `public_html/`, not inside it
|
|
|
|
|
+
|
|
|
|
|
+This exact layout matches how the PHP files resolve `../src/bootstrap.php` and `../data/...`.
|
|
|
|
|
+
|
|
|
|
|
+## What Must Be Public And What Must Stay Private
|
|
|
|
|
+
|
|
|
|
|
+Public in the web root:
|
|
|
|
|
+
|
|
|
|
|
+- `index.php`
|
|
|
|
|
+- `styles.css`
|
|
|
|
|
+- `app.js`
|
|
|
|
|
+- `openapi.yaml`
|
|
|
|
|
+- `admin/`
|
|
|
|
|
+- `api/`
|
|
|
|
|
+- `docs/`
|
|
|
|
|
+
|
|
|
|
|
+Private, outside the public web root:
|
|
|
|
|
+
|
|
|
|
|
+- `src/`
|
|
|
|
|
+- `data/config.json`
|
|
|
|
|
+- `data/state.json`
|
|
|
|
|
+- `data/alert_log.json`
|
|
|
|
|
+
|
|
|
|
|
+Do not place `data/` inside the public web root if you can avoid it. Those files contain credentials, live state, and alert history.
|
|
|
|
|
+
|
|
|
|
|
+## Deployment Steps
|
|
|
|
|
+
|
|
|
|
|
+### 1. Prepare the files
|
|
|
|
|
+
|
|
|
|
|
+From this repository, you need these folders:
|
|
|
|
|
+
|
|
|
|
|
+- `public/`
|
|
|
|
|
+- `src/`
|
|
|
|
|
+- `data/`
|
|
|
|
|
+
|
|
|
|
|
+You do not need `docs/` on the server for runtime operation. The `docs/` folder in the repository is only Markdown documentation for developers.
|
|
|
|
|
+
|
|
|
|
|
+### 2. Upload the application
|
|
|
|
|
+
|
|
|
|
|
+Using FTP, SFTP, or your hosting file manager:
|
|
|
|
|
+
|
|
|
|
|
+- upload `src/` outside the public web root
|
|
|
|
|
+- upload `data/` outside the public web root
|
|
|
|
|
+- upload the contents of `public/` into the public web root
|
|
|
|
|
+
|
|
|
|
|
+For a typical shared host that means:
|
|
|
|
|
+
|
|
|
|
|
+- repo `src/` -> server `~/src/`
|
|
|
|
|
+- repo `data/` -> server `~/data/`
|
|
|
|
|
+- repo `public/*` -> server `~/public_html/`
|
|
|
|
|
+
|
|
|
|
|
+### 3. Set permissions
|
|
|
|
|
+
|
|
|
|
|
+PHP must be able to write to `data/` and the JSON files in it.
|
|
|
|
|
+
|
|
|
|
|
+Typical safe defaults:
|
|
|
|
|
+
|
|
|
|
|
+- directories: `755` or `775`
|
|
|
|
|
+- files: `644` or `664`
|
|
|
|
|
+
|
|
|
|
|
+If the host runs PHP under your own account, `755/644` is often enough. If writes fail, adjust group write permissions first before considering anything more permissive.
|
|
|
|
|
+
|
|
|
|
|
+The app needs write access for:
|
|
|
|
|
+
|
|
|
|
|
+- `data/config.json`
|
|
|
|
|
+- `data/state.json`
|
|
|
|
|
+- `data/alert_log.json`
|
|
|
|
|
+
|
|
|
|
|
+### 4. Set the PHP version
|
|
|
|
|
+
|
|
|
|
|
+In the hosting control panel, select PHP `8.1` or newer for the domain/subdomain.
|
|
|
|
|
+
|
|
|
|
|
+### 5. Open the app
|
|
|
|
|
+
|
|
|
|
|
+After upload, these URLs should work:
|
|
|
|
|
+
|
|
|
|
|
+- `/`
|
|
|
|
|
+- `/admin/`
|
|
|
|
|
+- `/api/v1/status.php`
|
|
|
|
|
+- `/docs/`
|
|
|
|
|
+- `/openapi.yaml`
|
|
|
|
|
+
|
|
|
|
|
+Examples:
|
|
|
|
|
+
|
|
|
|
|
+- `https://monitor.example.com/`
|
|
|
|
|
+- `https://monitor.example.com/admin/`
|
|
|
|
|
+- `https://monitor.example.com/api/v1/status.php`
|
|
|
|
|
+
|
|
|
|
|
+### 6. Replace the default credentials
|
|
|
|
|
+
|
|
|
|
|
+The example files ship with placeholder credentials. After the first login, immediately change:
|
|
|
|
|
+
|
|
|
|
|
+- admin username
|
|
|
|
|
+- admin password
|
|
|
|
|
+- API bearer token
|
|
|
|
|
+
|
|
|
|
|
+You can do that in `/admin/`.
|
|
|
|
|
+
|
|
|
|
|
+### 7. Configure the application
|
|
|
|
|
+
|
|
|
|
|
+In the admin panel, configure:
|
|
|
|
|
+
|
|
|
|
|
+- app name
|
|
|
|
|
+- timezone
|
|
|
|
|
+- dashboard refresh interval
|
|
|
|
|
+- email sender
|
|
|
|
|
+- webhook targets
|
|
|
|
|
+- email recipients
|
|
|
|
|
+- machines
|
|
|
|
|
+- slots
|
|
|
|
|
+- sensor calibration values
|
|
|
|
|
+- alert thresholds
|
|
|
|
|
+
|
|
|
|
|
+The JSON structure is documented in [CONFIG.md](./CONFIG.md).
|
|
|
|
|
+
|
|
|
|
|
+### 8. Connect the sensor clients
|
|
|
|
|
+
|
|
|
|
|
+Each ESP32 or other sensor client should send readings to:
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+POST https://your-domain.example/api/v1/readings.php
|
|
|
|
|
+Authorization: Bearer <your-token>
|
|
|
|
|
+Content-Type: application/json
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+The request and response format is documented in [API.md](./API.md).
|
|
|
|
|
+
|
|
|
|
|
+### 9. Run a deployment check
|
|
|
|
|
+
|
|
|
|
|
+Verify all of the following:
|
|
|
|
|
+
|
|
|
|
|
+- dashboard loads without PHP errors
|
|
|
|
|
+- admin login works
|
|
|
|
|
+- saving config works
|
|
|
|
|
+- `data/state.json` updates after a test reading
|
|
|
|
|
+- webhook delivery works if configured
|
|
|
|
|
+- email delivery works if configured
|
|
|
|
|
+- `/api/v1/status.php` returns JSON
|
|
|
|
|
+- `/docs/` loads Swagger UI
|
|
|
|
|
+
|
|
|
|
|
+## First Live Test
|
|
|
|
|
+
|
|
|
|
|
+Use one manual API call after deployment:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+curl -X POST https://your-domain.example/api/v1/readings.php \
|
|
|
|
|
+ -H 'Authorization: Bearer YOUR_TOKEN' \
|
|
|
|
|
+ -H 'Content-Type: application/json' \
|
|
|
|
|
+ -d '{
|
|
|
|
|
+ "machine_id": "automat-lobby",
|
|
|
|
|
+ "sensor_id": "fach-a1",
|
|
|
|
|
+ "distance_mm": 184
|
|
|
|
|
+ }'
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+If that works, the dashboard should shortly show the new state.
|
|
|
|
|
+
|
|
|
|
|
+## Troubleshooting
|
|
|
|
|
+
|
|
|
|
|
+### Dashboard loads, but saving config fails
|
|
|
|
|
+
|
|
|
|
|
+Cause:
|
|
|
|
|
+
|
|
|
|
|
+- `data/` is not writable by PHP
|
|
|
|
|
+
|
|
|
|
|
+Check:
|
|
|
|
|
+
|
|
|
|
|
+- directory permissions
|
|
|
|
|
+- file ownership
|
|
|
|
|
+- hosting PHP user
|
|
|
|
|
+
|
|
|
|
|
+### PHP errors about missing `src/bootstrap.php`
|
|
|
|
|
+
|
|
|
|
|
+Cause:
|
|
|
|
|
+
|
|
|
|
|
+- `src/` was uploaded into the wrong place
|
|
|
|
|
+
|
|
|
|
|
+Fix:
|
|
|
|
|
+
|
|
|
|
|
+- place `src/` next to `public_html/`, not inside it
|
|
|
|
|
+
|
|
|
|
|
+### API works locally but not on shared hosting
|
|
|
|
|
+
|
|
|
|
|
+Check:
|
|
|
|
|
+
|
|
|
|
|
+- PHP version
|
|
|
|
|
+- whether `Authorization` headers are forwarded by the host
|
|
|
|
|
+- whether HTTPS is used
|
|
|
|
|
+
|
|
|
|
|
+The app already checks both `HTTP_AUTHORIZATION` and `REDIRECT_HTTP_AUTHORIZATION`, which helps on many Apache-based hosts.
|
|
|
|
|
+
|
|
|
|
|
+### `/docs/` does not render
|
|
|
|
|
+
|
|
|
|
|
+Cause:
|
|
|
|
|
+
|
|
|
|
|
+- the Swagger UI page loads its assets from `cdn.jsdelivr.net`
|
|
|
|
|
+
|
|
|
|
|
+Fix:
|
|
|
|
|
+
|
|
|
|
|
+- allow outbound access to the CDN
|
|
|
|
|
+- or replace the hosted Swagger assets with local files later
|
|
|
|
|
+
|
|
|
|
|
+## Recommended Go-Live Checklist
|
|
|
|
|
+
|
|
|
|
|
+- deploy at the domain root, not in a subfolder
|
|
|
|
|
+- keep `src/` and `data/` outside the public web root
|
|
|
|
|
+- ensure `data/` is writable
|
|
|
|
|
+- replace all demo credentials
|
|
|
|
|
+- test one real API reading
|
|
|
|
|
+- verify alerts before production use
|