Files
Project-SDE-WP-Suite/DEPLOYMENT.md
n.siegfried 3d4402c88c Switch feedback reverse proxy from IIS to NGINX
- Add nginx-wp-suite.conf: static site + /api/feedback proxy to the Power
  Automate trigger (SNI on, Host header, POST-only, body cap)
- Remove IIS web.config
- Update feedback-config.js comment and DEPLOYMENT.md to the NGINX setup

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:46:35 -07:00

165 lines
6.2 KiB
Markdown

# Deployment & Feedback Collection
The Work Package Suite is a **static client-side app** — plain HTML, CSS, and
JavaScript. There is no build step and no database.
## Hosting it behind the firewall
Copy the whole folder to any internal web server and serve it over HTTP(S):
- **IIS / Apache / nginx** — drop the files in the site root. `index.html` is the
entry point.
- **SharePoint / network share** — works too, as long as the files are served
over `http(s)://` (not opened as `file://...`). Serving over HTTP makes
`localStorage` and the embedded Work Package Creator (an `<iframe>`) behave
reliably.
The app makes **no outbound internet calls** — the logo and all scripts are
local, and the previous Google-Fonts dependency has been removed (fonts now fall
back to system UI fonts). So it runs fully air-gapped behind a corporate
firewall.
## Where data lives
By default **everything is stored in each user's own browser** (`localStorage`):
the SOP configuration, the saved Work Packages, the usage logs, and all feedback
/ comments. This means:
- Data is **per-user and per-device** — it is not shared between people, and
clearing browser data erases it.
- Nothing is transmitted anywhere unless you enable central collection (below).
## Feedback collection
There are two layers, and they work together.
### 1. Export / Import (no server required — works today)
Every feedback surface has **Export** and **Import** buttons:
- Home page → *Leave Feedback* panel
- SOP Configuration → *Step Comments* (header button)
- Work Package Creator → *Comments* drawer
A reviewer clicks **Export** to download a JSON file and sends it to you; you
click **Import** on your machine to merge everyone's feedback together (imports
de-duplicate, so re-importing is safe). This needs zero infrastructure and works
behind any firewall.
### 2. Central auto-collection (optional — flip on when hosting is known)
To also gather every submission automatically into one place, set a single value
in [`feedback-config.js`](feedback-config.js):
```js
window.FEEDBACK_ENDPOINT = 'https://your-endpoint-url';
```
When set, each submission is additionally `POST`ed as JSON to that URL (saving
locally still happens, so a failed/disabled endpoint never loses feedback). The
endpoint can be either of:
#### Option A — a small backend on your host
Any server that can run code and append the request body to a file you can
download. Example (Node/Express):
```js
const express = require('express');
const fs = require('fs');
const app = express();
app.use(express.json());
app.post('/feedback', (req, res) => {
fs.appendFileSync('feedback.jsonl', JSON.stringify(req.body) + '\n');
res.sendStatus(204);
});
app.listen(8080);
```
Each line of `feedback.jsonl` is one submission; download it anytime. (PHP/
Python/ASP.NET equivalents are a few lines too.)
#### Option B — Internal NGINX reverse proxy → Power Automate (the chosen setup)
The browser posts to a **same-origin** path `/api/feedback`; NGINX forwards that
to the Power Automate trigger. This avoids CORS entirely and keeps the secret
trigger URL off the client. `FEEDBACK_ENDPOINT` is already set to
`/api/feedback`, and [`nginx-wp-suite.conf`](nginx-wp-suite.conf) contains the
full server block.
**On the NGINX box (one-time, server admin):**
1. Copy the project files to the web root (e.g. `/var/www/wp-suite`).
2. Install [`nginx-wp-suite.conf`](nginx-wp-suite.conf) (e.g. into
`/etc/nginx/conf.d/`), and set `server_name`, the `ssl_certificate` paths
(internal cert), and the `root`.
3. In the `location = /api/feedback` block, replace the `proxy_pass` URL and the
`Host` header with your real trigger URL / region host (keep the full query
string incl. `sig=`).
4. `sudo nginx -t && sudo systemctl reload nginx`.
> Two NGINX details that matter: `proxy_ssl_server_name on;` (SNI is required for
> `*.logic.azure.com` or the TLS handshake fails) and the `Host` header set to
> the Azure region host. Both are already in the provided config.
**In Power Automate:**
1. Create a flow with the **"When an HTTP request is received"** trigger.
2. Set its **Request Body JSON Schema** to:
```json
{
"type": "object",
"properties": {
"app": { "type": "string" },
"page": { "type": "string" },
"submittedAt": { "type": "string" },
"type": { "type": "string" },
"name": { "type": "string" },
"author": { "type": "string" },
"text": { "type": "string" },
"step": { "type": "integer" },
"view": { "type": "string" },
"timestamp": { "type": "string" },
"ts": { "type": "string" },
"id": { "type": "string" },
"clientId": { "type": "string" }
}
}
```
> `name` is used by the home/SOP forms, `author` by the Work Package Creator.
> Map both into one "Submitted by" column with an expression like
> `coalesce(triggerBody()?['name'], triggerBody()?['author'])`.
3. Add an action — **Create item** (SharePoint list) or **Add a row into a
table** (Excel / Dataverse) — mapping the fields above.
4. Save; copy the generated **HTTP POST URL** into `web.config`
(`POWER_AUTOMATE_TRIGGER_URL`).
5. A Power App (or just the list/Excel) reads that store to show live comments.
Chain: `browser → /api/feedback (NGINX proxy) → Power Automate → SharePoint/Dataverse → Power App`.
The "downloadable file" is then just the Excel/SharePoint list, viewable live or
exported — all inside your corporate cloud.
### CORS note
If the endpoint is on a **different origin** than the site, it must return CORS
headers allowing the site's origin (e.g.
`Access-Control-Allow-Origin: https://wp-suite.yourcompany.local`). A Power
Automate HTTP trigger and a same-host backend both handle this cleanly; a
same-origin backend needs no CORS at all.
## Feedback payload shape
Each POST body looks like:
```json
{
"app": "Work Package Suite",
"page": "/work-package-suite.html",
"submittedAt": "2026-06-15T18:20:00.000Z",
"type": "sop_step_comment",
"name": "J. Park",
"text": "Consider adding a fiber WP type",
"step": 4
}
```
`type` is one of `home_feedback`, `sop_step_comment`, or `wp_review_comment`.