Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ USE_HTTPS=false
# SSL_CERT=/etc/letsencrypt/live/example.com/fullchain.pem
# SSL_KEY=/etc/letsencrypt/live/example.com/privkey.pem

# Express trust proxy configuration. Leave empty when running Tasker directly on
# the internet. Set to true (or a hop count like 1) when behind a reverse proxy.
# Accepts true/false, a hop count, or a proxy-addr value such as "loopback".
# TRUST_PROXY=true

# SMTP email settings (optional — can also be configured via the admin panel).
# Used to email dropdown/flag suggestions to the administrator instead of
# storing free-text user input on the server.
Expand All @@ -31,6 +36,10 @@ USE_HTTPS=false
# SMTP_FROM=tasker@example.com
# SMTP_TO=you@nhs.net

# Debug-only 2FA fallback: when true, failed 2FA emails log the code to server logs.
# Do NOT enable in production.
# ALLOW_2FA_LOG_FALLBACK=false

# Cloudflare Turnstile CAPTCHA (optional — omit to disable CAPTCHA).
# Register a site at https://dash.cloudflare.com/profile/api-tokens (Turnstile)
# and set the Site Key (public, sent to the browser) and Secret Key (private,
Expand Down
9 changes: 7 additions & 2 deletions docs/installation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Tasker — Installation Manual

**Version 1.14.0 — May 2026**
**Version 1.14.1 — May 2026**

---

Expand Down Expand Up @@ -99,12 +99,16 @@ nano .env # or use your preferred editor
| `PORT` | Port the application listens on | `3020` |
| `SESSION_SECRET` | A long, random secret string used to sign session cookies. **Must be set in production.** | Random (changes on every restart) |
| `NODE_ENV` | Set to `production` to enable secure (HTTPS-only) cookies | — |
| `TRUST_PROXY` | Express trust proxy setting. Leave empty when Tasker is directly exposed. Set to `true` or a hop count (e.g. `1`) when behind a reverse proxy so `X-Forwarded-For` and scheme headers are trusted. | — |
| `APP_URL` | Full public URL of the server (no trailing slash). Used to generate clickable review links in suggestion emails, plus canonical and crawler-facing URLs for the homepage, llms.txt, robots.txt, and sitemap.xml. | — |
| `SSL_CERT_DIR` | Directory containing Let's Encrypt certificate files | `/etc/letsencrypt/live/yourdomain` |
| `SSL_CERT` | Full path to the certificate chain file | `$SSL_CERT_DIR/fullchain.pem` |
| `SSL_KEY` | Full path to the private key file | `$SSL_CERT_DIR/privkey.pem` |
| `TURNSTILE_SITE_KEY` | Cloudflare Turnstile site key. When set (alongside `TURNSTILE_SECRET_KEY`), a CAPTCHA widget is displayed on the login and registration forms. Omit to disable Turnstile entirely. | — |
| `TURNSTILE_SECRET_KEY` | Cloudflare Turnstile secret key. Required when `TURNSTILE_SITE_KEY` is set. | — |
| `ALLOW_2FA_LOG_FALLBACK` | Debug-only: when `true`, logs admin 2FA codes if SMTP delivery fails. **Do not enable in production.** | — |

> **Upgrade note:** From v1.14.1 onward, set `TRUST_PROXY=1` (or `true`) if Tasker sits behind a reverse proxy. Otherwise Express will not trust forwarded client IP headers.

### Generating a session secret

Expand All @@ -120,6 +124,7 @@ Copy the output into your `.env` file as the `SESSION_SECRET` value.
PORT=3020
SESSION_SECRET=<output of the command above>
NODE_ENV=production
TRUST_PROXY=1
APP_URL=https://tasker.jahosi.co.uk
SSL_CERT_DIR=/etc/letsencrypt/live/yourdomain.example.com
```
Expand Down Expand Up @@ -285,7 +290,7 @@ The server detects SSL certificates automatically. If both `SSL_CERT` and `SSL_K

### Running behind a reverse proxy (HTTP internally)

If you terminate SSL at Nginx or Caddy and forward plain HTTP to Tasker, **do not** set `SSL_CERT` / `SSL_KEY` in `.env`. The application will listen on plain HTTP internally. The `trust proxy` setting is already configured so that `X-Forwarded-For` headers are respected.
If you terminate SSL at Nginx or Caddy and forward plain HTTP to Tasker, **do not** set `SSL_CERT` / `SSL_KEY` in `.env`. The application will listen on plain HTTP internally. Set `TRUST_PROXY=1` (or `true`) so that `X-Forwarded-For` and scheme headers are respected by Express.

---

Expand Down
10 changes: 6 additions & 4 deletions docs/technical-manual.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tasker — Technical Reference Manual v1.14.0</title>
<title>Tasker — Technical Reference Manual v1.14.1</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body {
Expand Down Expand Up @@ -107,7 +107,7 @@
<div class="page">

<h1>Tasker — Technical Reference Manual</h1>
<p class="subtitle">Version 1.14.0 &nbsp;·&nbsp; May 2026 &nbsp;·&nbsp; <em>Prepared in the role of Professor of Digital Engineering Product Design</em></p>
<p class="subtitle">Version 1.14.1 &nbsp;·&nbsp; May 2026 &nbsp;·&nbsp; <em>Prepared in the role of Professor of Digital Engineering Product Design</em></p>

<div class="toc">
<h2>Table of Contents</h2>
Expand Down Expand Up @@ -291,13 +291,15 @@ <h2 id="s5">5. Environment Configuration</h2>
<tr><td><code>APP_URL</code></td><td>Recommended</td><td>Full public base URL. Used for suggestion-review links plus canonical, Open Graph, <code>robots.txt</code>, <code>sitemap.xml</code>, and <code>llms.txt</code> output.</td></tr>
<tr><td><code>SESSION_SECRET</code></td><td><strong>Yes</strong></td><td>64+ random hex characters used to sign session cookies. If omitted, a random value is generated each restart — invalidating all sessions on every restart.</td></tr>
<tr><td><code>NODE_ENV</code></td><td><strong>Yes</strong></td><td>Set to <code>production</code> to enable <code>secure: true</code> on session cookies (HTTPS-only cookies).</td></tr>
<tr><td><code>TRUST_PROXY</code></td><td>No</td><td>Express trust proxy setting. Leave unset when Tasker is directly exposed; set to <code>true</code> or a hop count (e.g. <code>1</code>) when behind a reverse proxy so <code>X-Forwarded-For</code> and scheme headers are trusted.</td></tr>
<tr><td><code>ENCRYPTION_KEY</code></td><td>Recommended</td><td>64 hex characters (32 bytes). If set, task <code>notes</code> are encrypted with AES-256-GCM. If absent, notes are stored as plaintext.</td></tr>
<tr><td><code>SSL_CERT</code></td><td>For TLS</td><td>Path to PEM certificate file. If both <code>SSL_CERT</code> and <code>SSL_KEY</code> exist on disk, the server starts in HTTPS mode.</td></tr>
<tr><td><code>SSL_KEY</code></td><td>For TLS</td><td>Path to PEM private key file.</td></tr>
<tr><td><code>SSL_CERT_DIR</code></td><td>No</td><td>Directory shortcut — individual cert/key paths are derived from this if not overridden.</td></tr>
<tr><td><code>TASKER_DB_PATH</code></td><td>Tests only</td><td>Override the database path (e.g. <code>:memory:</code> or a temp file). Used by the test harness.</td></tr>
<tr><td><code>TURNSTILE_SITE_KEY</code></td><td>No</td><td>Cloudflare Turnstile site key. When both this and <code>TURNSTILE_SECRET_KEY</code> are set, a CAPTCHA widget is rendered on the login and registration forms. Omit to disable Turnstile entirely.</td></tr>
<tr><td><code>TURNSTILE_SECRET_KEY</code></td><td>No</td><td>Cloudflare Turnstile secret key used for server-side token verification. Required alongside <code>TURNSTILE_SITE_KEY</code>.</td></tr>
<tr><td><code>ALLOW_2FA_LOG_FALLBACK</code></td><td>No</td><td>Debug-only flag. When set to <code>true</code>, admin 2FA codes are logged if SMTP delivery fails. Do not enable in production.</td></tr>
</tbody>
</table>

Expand All @@ -308,7 +310,7 @@ <h2 id="s6">6. Server Entry Point — <code>src/server.ts</code></h2>
<h3>6.1 Startup Sequence</h3>
<ol>
<li><strong><code>dotenv/config</code></strong> is imported first as a side-effect, loading <code>.env</code> into <code>process.env</code>.</li>
<li>The Express <code>app</code> object is created and <code>trust proxy</code> is set to <code>1</code>, enabling correct IP detection behind a reverse proxy.</li>
<li>The Express <code>app</code> object is created and <code>trust proxy</code> is configured from <code>TRUST_PROXY</code> (or disabled by default), controlling whether <code>X-Forwarded-For</code> headers are trusted.</li>
<li><strong>SSL detection</strong>: The process checks whether both <code>SSL_CERT</code> and <code>SSL_KEY</code> files exist on disk. The <code>useHttps</code> boolean controls subsequent TLS-related behaviour.</li>
<li><strong>Helmet</strong> applies security headers. The CSP allows <code>'unsafe-inline'</code> for scripts (required by vanilla-JS inline event handlers in <code>app.js</code>) and <code>cdn.jsdelivr.net</code> (Chart.js). <code>upgradeInsecureRequests</code> is only included when running over HTTPS.</li>
<li><strong>JSON and URL-encoded body parsers</strong> are registered with a 1 MB request size limit.</li>
Expand Down Expand Up @@ -916,7 +918,7 @@ <h2 id="s23">23. Known Design Decisions &amp; Constraints</h2>

<hr>
<p style="text-align:center;font-size:.85rem;color:#9ca3af;margin-top:40px">
Tasker Technical Reference Manual &nbsp;·&nbsp; v1.14.0 &nbsp;·&nbsp; May 2026<br>
Tasker Technical Reference Manual &nbsp;·&nbsp; v1.14.1 &nbsp;·&nbsp; May 2026<br>
This document is stored in <code>docs/</code> and is not served by the application.
</p>

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tasker",
"version": "1.14.0",
"version": "1.14.1",
"description": "Anonymous task logger for healthcare staff",
"main": "dist/server.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion public/dpia.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
</style>
</head>
<body>
<a class="back-link" href="/" onclick="history.back();return false;">← Back</a>
<a class="back-link" href="/">← Back</a>
<h1>🛡️ Tasker — Data Protection Impact Assessment (DPIA)</h1>
<p><small>Version 1.14.0 — Completed 23 May 2026 &nbsp;|&nbsp; Application Version 1.14.0 &nbsp;|&nbsp; Prepared in accordance with UK GDPR Article 35 and ICO guidance</small></p>

Expand Down
4 changes: 2 additions & 2 deletions public/guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@
<div class="hero-icon">📱</div>
<h1>Tasker Quick Start Guide</h1>
<p>Everything you need to start recording tasks in under 5 minutes.</p>
<a class="back-btn" href="/" onclick="history.back();return false;">← Back to Tasker</a>
<a class="back-btn" href="/">← Back to Tasker</a>
</div>

<div class="page">
Expand Down Expand Up @@ -893,7 +893,7 @@ <h1>Tasker Quick Start Guide</h1>
&nbsp;·&nbsp;
<a href="/policy">Data &amp; Use Policy</a>
&nbsp;·&nbsp;
<a href="/" onclick="history.back();return false;">← Back to Tasker</a>
<a href="/">← Back to Tasker</a>
</p>
</footer>

Expand Down
2 changes: 1 addition & 1 deletion public/help.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</style>
</head>
<body>
<a class="back-link" href="/" onclick="history.back();return false;">← Back</a>
<a class="back-link" href="/">← Back</a>
<h1>❓ Tasker — Help &amp; User Guide</h1>
<p><small>Version 1.14.0 — May 2026</small></p>

Expand Down
4 changes: 2 additions & 2 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<meta name="twitter:image:alt" content="Tasker: anonymous workload logger for healthcare teams">
<title>Tasker — Anonymous workload logger for healthcare teams</title>
<link rel="stylesheet" href="/css/app.css">
<script type="application/ld+json">
<script type="application/ld+json" nonce="__CSP_NONCE__">
{
"@context": "https://schema.org",
"@type": "SoftwareApplication",
Expand Down Expand Up @@ -70,7 +70,7 @@
}
}
</script>
<script type="application/ld+json">
<script type="application/ld+json" nonce="__CSP_NONCE__">
{
"@context": "https://schema.org",
"@type": "FAQPage",
Expand Down
Loading