diff --git a/docs/DEVELOPMENT_AND_STAGING.md b/docs/DEVELOPMENT_AND_STAGING.md
index bc2cdd9..f56cb4d 100644
--- a/docs/DEVELOPMENT_AND_STAGING.md
+++ b/docs/DEVELOPMENT_AND_STAGING.md
@@ -6,7 +6,7 @@
|---|---|---|
| Windows | Source editing and Git workflow only | Not applicable |
| Rocky Linux | Docker development and production-like staging | `http://192.168.1.101:9190` |
-| Temporary VPS | Month-long user-acceptance staging behind Cloudflare, Nginx, and Authelia | `laikapstak.li` registered; Cloudflare delegation pending; services not started |
+| Temporary VPS | Month-long user-acceptance staging behind Cloudflare, Nginx, and Authelia | Public UAT operational at `https://laikapstak.li` with temporary synthetic data |
| Workplace production | Out of scope until reviewed and approved | Not documented here |
Rocky checkout:
@@ -123,7 +123,7 @@ The temporary VPS must not become another development checkout. The proposed rel
Windows source and Git -> Rocky build and verification -> immutable image + checksum -> VPS deployment
```
-Releases are manual during user acceptance and are identified by the source commit SHA. The VPS keeps WeatherTool in its own `/srv/weathertool` tree, publishes the application only to a loopback port, and relies on Nginx plus Authelia at the public boundary. See `VPS_STAGING_PLAN.md` before provisioning or changing the VPS.
+Releases are manual during user acceptance and are identified by the source commit SHA. The first installed release is `7dbc55b`. The VPS keeps WeatherTool in its own `/srv/weathertool` tree, publishes the application only to loopback ports, and relies on Nginx plus Authelia at the future public boundary. See `VPS_STAGING_PLAN.md` before changing the VPS deployment.
The committed templates live under `deploy/vps/`. They are not a second local
development environment. Validate them on Rocky, build the exact Git revision,
diff --git a/docs/README.md b/docs/README.md
index 3d82543..0f01685 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -13,7 +13,12 @@ This directory contains the working documentation for the WeatherTool modernizat
- Faktiskā symbol placement is automatic after manual image selection and is anchored to each rendered temperature badge.
- The first **Ūdens temperatūra** workspace is implemented with manual Latvian-named fields and required 1920×1080 and 3840×1440 exports; visual calibration remains in progress.
- Confirmed local Monda Regular/Bold files provide interface and generated-graphic typography; weather symbols use normalized transparent image assets.
-- The version-controlled temporary VPS UAT bundle has passed Compose, Authelia, image-build, container-health, loopback HTTP, and database-port-isolation checks on Rocky. VPS directories exist, but no WeatherTool service has been started.
+- Release `7dbc55b` was built and checksummed on Rocky, transferred to the VPS, verified, and loaded as the immutable `weathertool:7dbc55b` image.
+- The isolated VPS UAT stack is running and healthy: WeatherTool is bound to `127.0.0.1:8002`, Authelia to `127.0.0.1:9091`, and PostgreSQL has no host port. Public Nginx routing is not enabled yet.
+- Cloudflare delegation is active, strict origin TLS covers only `laikapstak.li` and `auth.laikapstak.li`, and the public Nginx/Authelia login flow is operational without changing the existing HOP site.
+- The VPS database contains a deliberately limited 14-day, 34-city synthetic dataset for newsroom visual testing. It must be cleared before authorized real-provider ingestion begins.
+- Approved 1920×1080 and 3840×1440 PNG production bases are now the rendering source for Faktiskā and Ūdens temperatūra; code draws only the changing values, selected weather symbols, and wind data over those fixed newsroom graphics.
+- Browser branding assets and Latvian Open Graph/Twitter metadata are included for favicon, Apple home-screen icon, and link-preview support. Public crawler access still depends on the Nginx/Authelia policy used for the metadata and preview image.
- This is not yet approved or hardened for workplace production.
## Documents
diff --git a/docs/UPDATE_ROADMAP.md b/docs/UPDATE_ROADMAP.md
index 9846402..2d1e878 100644
--- a/docs/UPDATE_ROADMAP.md
+++ b/docs/UPDATE_ROADMAP.md
@@ -7,7 +7,7 @@ This document tracks proposed WeatherTool improvements. Work should be delivered
- **Windows development:** source editing and Git workflow only; Docker runtime testing is performed on Rocky.
- **Rocky staging:** production-like Docker deployment at `http://192.168.1.101:9190`.
- **Git over SSH:** Windows pushes reviewed commits to a private bare repository on Rocky; the Rocky staging checkout pulls those commits and rebuilds.
-- **Temporary VPS staging:** proposed month-long external user acceptance behind Cloudflare, Nginx, and Authelia; not yet provisioned.
+- **Temporary VPS staging:** release `7dbc55b` is publicly operational behind Cloudflare strict TLS, Nginx, and Authelia with a limited 14-day synthetic dataset.
- **Workplace production:** remains separate until changes are reviewed, tested, and explicitly approved for workplace use.
Do not synchronize `.env`, database directories, generated dependencies, build output, or provider credentials between machines.
@@ -143,20 +143,23 @@ Status: pending
## Phase 8 — Temporary VPS user acceptance
-Status: planned
+Status: in progress
- [x] Document the proposed isolated VPS topology and trusted Rocky-to-VPS release flow.
-- [ ] Choose the WeatherTool and Authelia hostnames and create their Cloudflare DNS records.
-- [ ] Record a read-only VPS inventory before provisioning and confirm ports, networks, storage, and capacity do not collide with existing services.
-- [ ] Provision a dedicated `/srv/weathertool` tree, Compose project, private network, database storage, and loopback-only application port.
-- [ ] Configure Authelia with one temporary shared account, Argon2id password storage, rate limiting, and temporary IP bans.
-- [ ] Add host-specific TLS certificates and Nginx authorization routing without weakening the existing Cloudflare-only firewall boundary.
-- [ ] Build and verify a commit-addressed immutable image on Rocky, then transfer its image archive and checksum to the VPS.
-- [ ] Verify authentication, direct-origin blocking, application health, generated PNG downloads, backups, logs, and rollback.
+- [x] Choose `laikapstak.li` and `auth.laikapstak.li`, create their proxied Cloudflare DNS records, and activate Cloudflare delegation.
+- [x] Record a read-only VPS inventory before provisioning and confirm ports, networks, storage, and capacity do not collide with existing services.
+- [x] Provision a dedicated `/srv/weathertool` tree, Compose project, private network, database storage, and loopback-only application and Authelia ports.
+- [x] Configure Authelia with one temporary shared account, Argon2id password storage, rate limiting, and temporary IP bans.
+- [x] Add an exact-host Cloudflare origin certificate and Nginx authorization routing without disrupting the existing HOP site.
+- [x] Build and verify commit-addressed image `weathertool:7dbc55b` on Rocky, then transfer and checksum-verify its image archive on the VPS.
+- [ ] Complete UAT verification: public authentication and application health pass; direct-origin blocking, logout, throttling, PNG downloads, backups, logs, and rollback remain.
- [ ] Run the month-long user test with manual releases and record feedback before any workplace-production decision.
## Known current limitations
+- The new fixed production PNG bases and social metadata are implemented locally and require a Rocky build plus UAT release before newsroom validation.
+- Link-preview crawlers cannot authenticate through Authelia; the final Nginx policy must deliberately expose only the minimum preview metadata/assets if WhatsApp previews are required.
+
- Staging uses synthetic PostgreSQL station data.
- LVGMC forecast CSV fixtures are not yet available.
- HARMONIE GRIB fixtures are not yet available.
diff --git a/docs/VPS_STAGING_PLAN.md b/docs/VPS_STAGING_PLAN.md
index 8567a89..f7319ad 100644
--- a/docs/VPS_STAGING_PLAN.md
+++ b/docs/VPS_STAGING_PLAN.md
@@ -1,6 +1,6 @@
# Temporary VPS staging plan
-Status: **Deployment bundle validated on Rocky; VPS runtime directories created; services not started**
+Status: **Release `7dbc55b` publicly operational behind Cloudflare, Nginx, and Authelia with temporary synthetic data**
This document defines the next deployment stage for approximately one month of
newsroom-user testing. It records the intended boundary before any VPS changes
@@ -57,9 +57,11 @@ Temporary VPS
Cloudflare -> Nginx -> Authelia authorization -> WeatherTool
```
-The host root plus `releases/` and `backups/` now exist with owner
-`ubuntu:ubuntu` and mode `0750`. No Compose file, secret, image, database, or
-running WeatherTool service has been placed there yet.
+The host root plus `releases/` and `backups/` exist with owner `ubuntu:ubuntu`
+and mode `0750`. Release `7dbc55b` was transferred from Rocky, verified against
+its SHA-256 manifest, loaded as `weathertool:7dbc55b`, and installed with the
+reviewed deployment bundle. The dedicated Compose stack is now running; no
+existing HOP container, network, volume, port, or Nginx site was changed.
The VPS receives a built release artifact, not a development checkout. It gets
no credential or route for the Rocky Git repository, the private Forgejo
@@ -72,11 +74,11 @@ Proposed application root:
```text
/srv/weathertool/
compose.yml
- .env.staging # untracked, root-owned, mode 0600
+ .env.staging # untracked, ubuntu-owned, mode 0600
config/
authelia/
configuration.yml # no secret values committed
- users.yml # Argon2id hash; protected on the VPS
+ users_database.yml # Argon2id hash; protected on the VPS
data/
postgres/
authelia/
@@ -133,8 +135,13 @@ include and Authelia service. The application remains unchanged.
The selected application hostname is `laikapstak.li`; the authentication portal
will use `auth.laikapstak.li`. OVH delivered and activated the domain on
-2026-08-20 with registrar DNSSEC disabled. Cloudflare nameserver delegation and
-zone activation are still pending. Before DNS publication:
+2026-08-20 with registrar DNSSEC disabled. Proxied Cloudflare A records for both
+exact hostnames point to the VPS. OVH accepted the delegation change to
+`riya.ns.cloudflare.com` and `rocco.ns.cloudflare.com`; Cloudflare delegation is
+now active. A Cloudflare Origin CA certificate valid only for `laikapstak.li`
+and `auth.laikapstak.li` is installed with a root-owned mode-`0600` private key,
+and Cloudflare uses Full (strict) TLS. The dedicated Nginx site is enabled.
+Operational requirements are:
1. Add an isolated Nginx virtual host without changing existing hosts.
2. Install a certificate valid for the exact WeatherTool/Authelia hostname or
@@ -174,9 +181,37 @@ Validation completed on Rocky on 2026-08-20:
- the app returned HTTP 200 through its loopback-only host binding; and
- PostgreSQL had no host port.
-Nginx syntax/integration validation, full Authelia login testing, artifact
-transfer, VPS private startup, certificate installation, and public DNS remain
-later checkpoints.
+VPS progress completed on 2026-08-20:
+
+- release archive and deployment archive transferred from Rocky;
+- both SHA-256 checksums verified before loading;
+- immutable image `weathertool:7dbc55b` loaded successfully;
+- `.env.staging`, PostgreSQL password, three Authelia secrets, and the shared
+ account Argon2id hash created only on the VPS;
+- secret files restricted to mode `0600` and the user database to `0640`;
+- Compose configuration rendered successfully on the VPS;
+- dedicated backend and edge networks created;
+- PostgreSQL, WeatherTool, and Authelia all reported healthy;
+- WeatherTool returned HTTP 200 on `127.0.0.1:8002`;
+- Authelia returned HTTP 200 on `127.0.0.1:9091/api/health`; and
+- PostgreSQL remained internal with no host port.
+
+Additional public progress completed on 2026-08-20:
+
+- exact-host Cloudflare origin certificate and matching private key verified;
+- Nginx configuration validated successfully before reload;
+- Nginx reloaded without disrupting the existing HOP site;
+- the Authelia portal returned HTTP 200 through the private Nginx/TLS path;
+- an unauthenticated WeatherTool request returned the expected Authelia 302;
+- public browser login through `https://laikapstak.li` succeeded; and
+- a checksummed seed derived from release `7dbc55b` inserted 11,458 hourly
+ observations for 34 cities covering 14 days.
+
+The shortened seed exists only to support visual user testing. Before real API
+credentials or scheduled ingestion are enabled, clear the synthetic `weather`
+table in a controlled maintenance step while scheduled jobs remain disabled.
+Logout, throttling/ban recovery, direct-origin rejection, representative PNG
+downloads, and backup/rollback rehearsal remain acceptance checkpoints.
Known application constraint: provider clients are constructed during startup
even when `ENABLE_SCHEDULED_JOBS=false`. The synthetic UAT Compose file therefore
@@ -244,10 +279,7 @@ Proposed temporary-staging minimum:
## Decisions and prerequisites still open
-- Cloudflare nameserver delegation and zone activation.
-- Cloudflare origin certificate covering both selected hostnames.
-- Deployment account and whether normal releases use public SSH or Tailscale.
- Final session and backup-retention values.
-- Secure operator-side generation and delivery of the shared credential.
-- Nginx syntax validation against the VPS include/certificate layout.
+- Secure delivery of the generated shared credential to the three testers.
+- Controlled removal of synthetic observations before real-provider ingestion.
- Health/readiness behavior suitable for automated release verification.
diff --git a/web/index.html b/web/index.html
index bf8682e..71dddaa 100644
--- a/web/index.html
+++ b/web/index.html
@@ -1,12 +1,27 @@
-
+