AutoMate Technisch Help

StatusPage — Architectuur

De StatusPage Worker is een SvelteKit SSR-applicatie die draait op Cloudflare Workers. Ze combineert een publieke statusweergave met een OIDC-beveiligde admin-sectie en een cron-gedreven health-poller. De verbinding met AutoMate.API loopt uitsluitend via een Workers VPC Service binding — er is geen publieke route naar de API.

Cloudflare stack

Azure

Cloudflare

HTTPS

D1 binding

KV binding

VPC binding

cloudflared tunnel

VNet-intern

status.automate365.cloud\n(Custom Domain / proxied)

Cloudflare Worker\nSvelteKit SSR + scheduled()

D1 (SQLite)\nstatus-db

KV\nSESSIONS\n(sessies + token cache)

Workers VPC\nwebapi service binding\nID: 019eb803-…

cloudflared Container App\nP-Automate-Conn-CFTunnel-CA-Weu\n2 replicas, VNet-intern

App Service\np-automate-portal-webapi-webapp-weu\nprivate endpoint

Browser

Bindings — overzicht

Binding naam

Type

Resource

Doel

DB

D1 Database

status-db (ID: 621faeef-…)

Applicatiedata: modules, health, incidenten

SESSIONS

KV Namespace

fca90299-…

OIDC-sessies (8u TTL) + Entra API-token cache

webapi

VPC Service

ID 019eb803-…

AutoMate.API via cloudflared tunnel

ASSETS

Static Assets

.svelte-kit/cloudflare

SvelteKit client-bundle (JS, CSS)

Cron triggers

Er zijn twee cron-schedules geregistreerd in wrangler.jsonc:

Schedule

Trigger

Actie

* * * * *

Elke minuut

runHealthPoll() + rollUpDailySummaries()

0 * * * *

Elk uur (minuut 0)

rollUpDailySummaries() + pruneOldHealthRecords()

De elke-minuut-trigger doet ook een rollup van de huidige dag zodat het publieke dashboard de dagelijkse uptime-blokken meteen bijwerkt zonder een uur te wachten.

De cron-handler (src/lib/server/scheduled.ts) controleert event.cron en stuurt door naar de juiste functie:

export async function handleCron(event: ScheduledEvent, env: Env): Promise<void> { if (event.cron === '0 * * * *') { await rollUpDailySummaries(env); const pruned = await pruneOldHealthRecords(env); return; } // Elke minuut await runHealthPoll(env, log); await rollUpDailySummaries(env); }

Waarom een postbuild-script nodig is

@sveltejs/adapter-cloudflare v7 schrijft na vite build het volledige worker-bundle naar .svelte-kit/cloudflare-tmp/_worker.js en overschrijft vervolgens het bestand dat in wrangler.jsonc's main-veld staat (src/main.ts). Dat gegenereerde bundle exporteert alleen een fetch-handler — géén scheduled().

Cloudflare Workers roepen cron triggers aan via scheduled(), niet via fetch. Zonder extra stap missen cron triggers hun handler.

Het script scripts/inject-scheduled.mjs wordt uitgevoerd als postbuild-hook en overschrijft src/main.ts met een wrapper die:

  1. de gegenereerde SvelteKit fetch-handler re-exporteert uit _worker.js

  2. een scheduled()-handler toevoegt die doorstuurt naar handleCron

// AUTO-GENERATED door scripts/inject-scheduled.mjs — niet handmatig bewerken import sveltekitWorker from '../.svelte-kit/cloudflare-tmp/_worker.js'; import { handleCron } from './lib/server/scheduled'; export default { fetch: sveltekitWorker.fetch, async scheduled(event, env, ctx) { ctx.waitUntil(handleCron(event, env)); } };

OIDC-authenticatieflow (admin)

De admin-sectie vereist een geldige Azure AD-identiteit. De flow gebruikt de arctic-library voor authorization code + PKCE:

KVWorker /signin-oidcAzure AD (Entra)Worker /admin/loginBrowserKVWorker /signin-oidcAzure AD (Entra)Worker /admin/loginBrowserGET /admin/logingenerateState() + generateCodeVerifier()Set-Cookie sp_oidc_state + sp_oidc_verifier, redirect → EntraAuthorization request (PKCE)redirect → /signin-oidc?code=...&state=...GET /signin-oidc?code=...&state=...Valideer state cookieToken exchange (code + code_verifier)id_token + access_tokenDecode id_token → SessionUsersaveSession(sessionId, user, 8u TTL)Set-Cookie sp_session, redirect → /admin
  • De redirect URI is {url.origin}/signin-oidc (niet PUBLIC_BASE_URL) zodat lokale dev naar localhost terugkeert

  • De Entra-app registration heeft {origin}/signin-oidc als toegestane redirect URI

  • Sessies worden uitsluitend in KV opgeslagen met een TTL van 8 uur

  • De id_token wordt gedecodeerd zonder signature verification (safe: TLS + client secret authenticeren de token endpoint al)

Entra-app: ac3eb2dc-8631-45a3-b702-e167511070f2 in tenant 8f3d46f0-9151-4904-be93-69420b7d9d61

API-clientverbinding en tokencache

De Worker communiceert met AutoMate.API via client-credentials (machine-to-machine). Het Entra-token wordt gecached in KV om per-request tokenacquisitie te vermijden:

// src/lib/server/api-client.ts const TOKEN_CACHE_KEY = 'api-token:client-credentials'; export async function getApiAccessToken(env: Env): Promise<string> { const cached = await env.SESSIONS.get(TOKEN_CACHE_KEY, 'json'); // Refresh 60 seconden voor expiry if (cached?.expiresAt - 60 > Math.floor(Date.now() / 1000)) { return cached.accessToken; } // … client_credentials flow → cache in KV }

De werkelijke HTTP-aanroep verloopt via env.webapi.fetch(...) met de echte Azure App Service-hostname als URL. Zie StatusPage — Workers VPC en CFTunnel voor de reden achter deze hostname-eis.

Security headers

src/hooks.server.ts voegt op elke response de volgende headers toe:

Header

Waarde

X-Frame-Options

DENY

X-Content-Type-Options

nosniff

Referrer-Policy

strict-origin-when-cross-origin

Custom domain

status.automate365.cloud is geconfigureerd als custom_domain: true in wrangler.jsonc. Wrangler beheert automatisch een proxied CNAME-record in Cloudflare DNS en voorziet het domein van Universal SSL. Bij de eerste deploy met dit record vervangt Wrangler een eventueel bestaand DNS-record (de voormalige Railway-configuratie).

Last modified: 25 June 2026