Accans

Changelog

Full version-by-version changelog of the Digital Sovereignty Heatmap.

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]

[0.2.0] - 2026-05-26

On-site changelog

  • New /[locale]/changelog page (NL + EN) rendering the user-facing update history. Source of truth: apps/web/src/lib/changelog.ts (typed, kept separate from this technical CHANGELOG.md).
  • Footer badge "Bijgewerkt: " / "Updated: " on every page, sourced from the latest changelog entry, linking to /changelog.
  • /changelog added to sitemap.xml with NL/EN hreflang alternates.

Vendor-database review — 2026-05-26

Net result: 1679 → 1700 vendor records. Source of truth: apps/web/data/vendors.seed.json. One-shot migration script: apps/web/scripts/migrate-vendors-2026-05.ts.

Added

  • Schema fields on Vendor (additive, non-breaking): ultimate_parent_country (optional ISO-2), sovereignty_mode (vendor-hosted-eu / self-host / oss-distributed / vendor-hosted-non-eu), eu_classification (eu-strict / eea / efta / eu-adjacent). Back-filled for all existing records.
  • 27 new EU vendors: CMP (Didomi, Axeptio, consentmanager.net) — SMS (TextMagic, SMSAPI) — Monitoring (Dynatrace, Pandora FMS) — Time tracking (TimeCamp, TimeTac) — Low-code (Make.com, Ninox, SeaTable) — Marketing (MailerLite) — CMS (Hygraph) — Translation (memoQ, Phrase TMS, Wordbee, Across) — Fintech (Trade Republic) — Helpdesk (Aircall) — Healthcare (Nedap Healthcare) — AI coding (JetBrains AI Assistant) — Notes (Bear) — Scheduling (Pretix, Bookingkit) — Enterprise social (LumApps, Talkspirit).
  • Invariant test suite vendor-invariants.test.ts — 9 tests pinning: no EU sentinel HQ without explicit sovereignty_mode, no >2 categories without allow-list, no duplicate (name, category) pairs, no Dutch ' or ' translation-bug pattern in description_en, ISO-3166-1 alpha-2 country codes, HTTPS-only websites, and the May-2026 problem-record outcomes.
  • ADR-001 — policy for borderline EU-provenance vendors (Optimizely, Sitecore, Talkdesk, Dashlane, Revolut, Yubico).

Changed (corrected HQs)

  • Hologic, Carestream Health, Wrike, WordPress (self-host) reclassified EU → US. Wrike now carries ultimate_parent_country=US (Symphony Industrial).
  • RustDesk → CN with sovereignty_mode=oss-distributed. Logseq → SG, oss-distributed. Synology Drive (on-prem) → TW, self-host.
  • Bitrix24 → CY with ultimate_parent_country=RU disclosed in description.
  • Wire (both collaboration + messaging records) corrected to CH, eu_classification=efta.
  • Directus → US (ultimate_parent_country=US, sovereignty_mode=self-host); the duplicate cms-categorised record was removed in favour of the low-code entry.
  • SumUp → GB with eu_classification=eu-adjacent; the duplicate sumup-payments record removed.
  • European-classification tags rolled out: 57 Swiss vendors → efta, 29 Norwegian/Icelandic → eea, 4 Ukrainian → eu-adjacent, 1159 EU-27 → eu-strict. headquarters_region left at EU deliberately so the scoring engine (10+ === "EU" checks across dimensions, drivers, migration, suggestions) keeps its current behaviour.

Removed

  • epic-eu (real HQ Verona WI — epic-ehr US incumbent retained)
  • sumup-payments (merged into sumup)
  • directus cms-variant (merged into directus-lowcode)
  • soffos-office (duplicate of softmaker-office in the same category)
  • adyen and mollie from erp-finance — payments processors, not ERPs. Both still listed under payments (and e-commerce for Adyen).

Earlier under [Unreleased]

Added

  • New category: writing-tools (Schrijfhulp & Grammatica) with LanguageTool as EU alternative
  • New vendors: Backblaze (storage-backup), Grammarly (writing-tools), Luminar Neo (design)
  • EU alternative mappings for Backblaze, Grammarly, and Luminar Neo

Fixed

  • Pinned aquasecurity/trivy-action to @0.30.0 (was @master — supply chain risk)
  • Dockerfile: resilient native addon copy handles pnpm hoisting variations
  • Defensive JSON parsing in mapVendorRow (try/catch instead of bare JSON.parse)
  • Map and Alternatives pages: added error state with retry button (was silent failure)
  • Accessibility: added aria-label to map country panel close button
  • Copy: consistent Dutch wording in map disclaimer

Security

  • Red-team review completed: PASS across all 5 perspectives (architecture, security, test quality, devops, UX)
  • No blockers found; 4 majors identified and remediated
  • Full findings documented in REVIEW.md

[0.1.0] — Unreleased

Added

  • Vendor expansion: ~130 vendors across 20 categories (was ~105 in 16)
  • 4 new categories: Projectmanagement (business), Muziek streaming, Video streaming, Notities & taken (personal)
  • ~24 new vendors: project management (OpenProject, Taiga, Plane, Jira, Confluence, Notion, Linear, Asana), music streaming (Deezer, Spotify, Tidal, Apple Music, YouTube Music), video streaming (NLZIET, NPO Start, Netflix, YouTube, Disney+), notes & tasks (Joplin, Standard Notes, Obsidian, Apple Notes, Google Keep), plus LinkedIn, Instagram, TikTok (social media) and Safari (browser)
  • Direct vendor recommendations: concrete "Gmail → Stap over naar Tuta" suggestions with specific Dutch-language reasons per vendor
  • VendorRecommendation interface and generateVendorRecommendations() in @ds-heatmap/core
  • RecommendationList component for rendering recommendations in results
  • Personal block: 8 new personal categories (E-mail, Messaging, Cloud Storage, VPN, Password Manager, Browser, Social Media, Desktop OS)
  • Separate scoring: business and personal assessments computed and displayed independently
  • 2 new personal scenarios: Privé Soeverein, Privé Hybride
  • block field on Category schema ("business" | "personal")
  • DEFAULT_PERSONAL_CATEGORY_WEIGHTS and CRITICAL_PERSONAL_CATEGORIES
  • Database migration for existing DBs (adds block column)

Changed

  • Recommendation system: replaced abstract driver-level suggestions with direct per-vendor recommendations
  • Removed DriverSuggestion type, suggestions field on Driver, and enrichDriversWithSuggestions()
  • Business category weights renormalised for 9 categories (added project-management at 0.066)
  • Personal category weights redistributed for 11 categories (equal ~0.0909 each)
  • notes-tasks added to CRITICAL_PERSONAL_CATEGORIES
  • Wizard vendor selection split into "Zakelijk" and "Privé" sections
  • Results page shows separate score panels per block with recommendation section
  • Existing business scenarios updated with new vendors
  • Telemetry allowlist expanded with all new vendor and category slugs

[0.1.0] - 2026-02-27

Added

  • Three-step assessment wizard: vendor selection → context → results with animated transitions
  • Deterministic scoring engine: 5 sovereignty dimensions (JES, DRS, CKS, PLS, SRS), category-weighted aggregation, risk drivers
  • Vendor knowledgebase with SQLite (better-sqlite3) — 32 vendors, 8 categories, 3 scenarios
  • Zod schemas for Category, Vendor, and Scenario in @ds-heatmap/core
  • API routes: GET /api/vendors, GET /api/categories, GET /api/scenarios, GET /api/health
  • Vendor filtering by category (?category=) and search (?q=)
  • Auto-seeding: database is seeded from JSON on first access
  • CLI seed script: pnpm seed / pnpm seed --force
  • Board memo generation: "Genereer bestuursmemo" button on results page → POST /api/memo → print-friendly /memo page
  • Dutch-language deterministic template with score-dependent executive summary, risk drivers, and recommendations
  • Optional Claude AI integration (CLAUDE_ENABLED=true) with automatic fallback to template
  • In-memory token-bucket rate limiter for /api/memo (5 burst, 1/10s refill per IP)
  • Print/PDF-friendly layout with @media print styles (A4)
  • Privacy-preserving telemetry: aggregated counters only, no raw events or PII stored
  • Telemetry disabled by default (TELEMETRY_ENABLED=false); double opt-in (server + user)
  • Strict allowlist validation: event names, vendor/category slugs, context enums, score bands (0-33/34-66/67-100)
  • /trends page with k-anonymous community data (buckets < K_ANON_THRESHOLD grouped as "Other")
  • Footer telemetry toggle with clear privacy copy
  • POST /api/telemetry endpoint with rate limiting and Zod validation
  • GET /api/trends endpoint with k-anonymity filter
  • metrics_counters SQLite table for aggregated counter storage
  • Release workflow: tag → build + Trivy scan → push to GHCR → GitHub Release with CHANGELOG notes
  • Structured JSON logger for server-side components
  • Initial project scaffold: Next.js 15 (App Router) + TypeScript + Tailwind CSS + shadcn/ui
  • pnpm monorepo with apps/web and packages/core
  • Multi-stage Dockerfile with non-root runtime user
  • Docker Compose with Caddy reverse proxy (auto-HTTPS capable)
  • GitHub Actions CI: lint, typecheck, test, build, Trivy scan, gitleaks, dependency audit

Security

  • Next.js middleware with security headers: CSP, X-Frame-Options DENY, X-Content-Type-Options nosniff, Referrer-Policy, Permissions-Policy
  • Request body size limits on all POST endpoints (16 KB for memo, 2 KB for telemetry)
  • Rate limiting per client IP on POST endpoints (in-memory token bucket)
  • Zod schema validation on all POST request bodies
  • Docker: read-only filesystem, resource limits (512 MB / 1 CPU), restrictive data directory permissions (750)
  • OCI image labels for GHCR metadata
  • No prompt payloads logged in Claude integration
  • No PII stored in telemetry (counters only, no IPs, no sessions)
Back to documentationThis document is a static snapshot of the canonical source in our codebase. Updates are published with every new build.
Changelog · Digital Sovereignty Heatmap